diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Constants/FormDataFields.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Constants/Internal/FormDataFields.cs
similarity index 100%
rename from src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Constants/FormDataFields.cs
rename to src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Constants/Internal/FormDataFields.cs
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Constants/SignAlgorithms.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Constants/SignAlgorithms.cs
new file mode 100644
index 00000000..56ffe932
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Constants/SignAlgorithms.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Constants
+{
+ public static class SignAlgorithms
+ {
+ ///
+ /// WECHATPAY2-SHA256-RSA2048。
+ ///
+ public const string WECHATPAY2_SHA256_RSA2048 = "WECHATPAY2-SHA256-RSA2048";
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventDecryptionExtensions.cs
similarity index 96%
rename from src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventExtensions.cs
rename to src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventDecryptionExtensions.cs
index 73afbc90..fdc60163 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventDecryptionExtensions.cs
@@ -3,9 +3,9 @@
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{
///
- /// 为 提供回调通知事件的扩展方法。
+ /// 为 提供回调通知事件敏感数据解密的扩展方法。
///
- public static class WechatTenpayClientEventExtensions
+ public static class WechatTenpayClientEventDecryptionExtensions
{
///
/// 反序列化得到 对象。
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs
new file mode 100644
index 00000000..8c51113a
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Text;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
+{
+ ///
+ /// 为 提供回调通知事件签名验证的扩展方法。
+ ///
+ public static class WechatTenpayClientEventVerificationExtensions
+ {
+ ///
+ /// 验证回调通知事件签名。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_1.shtml
+ ///
+ ///
+ ///
+ /// 微信回调通知中的 Wechatpay-Timestamp 字段。
+ /// 微信回调通知中的 Wechatpay-Nonce 字段。
+ /// 微信回调通知中请求正文。
+ /// 微信回调通知中的 Wechatpay-Signature 字段。
+ /// 微信回调通知中的 Wechatpay-Serial 字段。
+ ///
+ public static bool VerifyEventSignature(
+ this WechatTenpayClient client,
+ string callbackTimestamp,
+ string callbackNonce,
+ string callbackBody,
+ string callbackSignature,
+ string callbackSerialNumber)
+ where TResponse : WechatTenpayResponse
+ {
+ if (client == null) throw new ArgumentNullException(nameof(client));
+ if (callbackTimestamp == null) throw new ArgumentNullException(nameof(callbackTimestamp));
+ if (callbackNonce == null) throw new ArgumentNullException(nameof(callbackNonce));
+ if (callbackBody == null) throw new ArgumentNullException(nameof(callbackBody));
+ if (callbackSignature == null) throw new ArgumentNullException(nameof(callbackSignature));
+ if (callbackSerialNumber == null) throw new ArgumentNullException(nameof(callbackSerialNumber));
+
+ if (client.WechatCertificateStorer == null)
+ {
+ throw new Exceptions.WechatTenpayResponseVerificationException($"You must set an instance of `{nameof(Settings.ICertificateStorer)}` at first.");
+ }
+ else
+ {
+ string? certificate = client.WechatCertificateStorer.Get(callbackSerialNumber);
+ if (certificate == null)
+ throw new Exceptions.WechatTenpayResponseVerificationException("Cannot get certificate by the serial number, may not be stored.");
+
+ string? publicKey = null;
+ try
+ {
+ publicKey = Utilities.RSAUtility.ExportPublicKey(certificate);
+ }
+ catch (Exception ex)
+ {
+ throw new Exceptions.WechatTenpayResponseVerificationException("Cannot get public key of the certificate, may not be a valid certificate data.", ex);
+ }
+
+ try
+ {
+ return Utilities.RSAUtility.VerifyWithSHA256(
+ publicKey: publicKey,
+ plainText: GetPlainTextForSignature(timestamp: callbackTimestamp, nonce: callbackNonce, body: callbackBody),
+ signature: callbackSignature
+ );
+ }
+ catch (Exception ex)
+ {
+ throw new Exceptions.WechatTenpayResponseVerificationException("Verify event signature failed.", ex);
+ }
+ }
+ }
+
+ private static string GetPlainTextForSignature(string timestamp, string nonce, string body)
+ {
+ return $"{timestamp}\n{nonce}\n{body}\n";
+ }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteBillExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteBillExtensions.cs
index ac377597..17b7fd17 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteBillExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteBillExtensions.cs
@@ -108,6 +108,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_8.shtml
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter5_1_19.shtml
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_9_3.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_3.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter4_3.shtml
///
///
///
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteEcommerceFundBalanceExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteEcommerceFundBalanceExtensions.cs
index ed344dc7..2b0ac1bc 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteEcommerceFundBalanceExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteEcommerceFundBalanceExtensions.cs
@@ -18,6 +18,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
/// 异步调用 [GET] /ecommerce/fund/balance/{sub_mchid} 接口。
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_1.shtml
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_8_1.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter5_1.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter5_2.shtml
///
///
///
@@ -40,6 +42,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 异步调用 [GET] /ecommerce/fund/enddaybalance/{sub_mchid} 接口。
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_2.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter5_3.shtml
///
///
///
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteEcommerceFundWithdrawExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteEcommerceFundWithdrawExtensions.cs
index 23a4a707..11c5a77a 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteEcommerceFundWithdrawExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteEcommerceFundWithdrawExtensions.cs
@@ -17,6 +17,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 异步调用 [POST] /ecommerce/fund/withdraw 接口。
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_8_2.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter6_1.shtml
///
///
///
@@ -37,6 +38,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 异步调用 [GET] /ecommerce/fund/withdraw/out-request-no/{out_request_no} 接口。
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_8_3.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter6_2.shtml
///
///
///
@@ -57,6 +59,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 异步调用 [GET] /ecommerce/fund/withdraw/{withdraw_id} 接口。
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_8_3.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter6_2.shtml
///
///
///
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundBalanceExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundBalanceExtensions.cs
index 74eceecc..cd6e0436 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundBalanceExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundBalanceExtensions.cs
@@ -17,6 +17,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 异步调用 [GET] /merchant/fund/balance/{account_type} 接口。
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_3.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter5_1.shtml
///
///
///
@@ -36,6 +37,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 异步调用 [GET] /merchant/fund/dayendbalance/{account_type} 接口。
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_7_4.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter5_2.shtml
///
///
///
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundIncomeRecordsExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundIncomeRecordsExtensions.cs
new file mode 100644
index 00000000..af509541
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundIncomeRecordsExtensions.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Flurl;
+using Flurl.Http;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
+{
+ ///
+ /// 为 提供来账识别相关的 API 扩展方法。
+ ///
+ public static class WechatTenpayClientExecuteMerchantFundIncomeRecordsExtensions
+ {
+ ///
+ /// 异步调用 [GET] /merchantfund/merchant/income-records 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_7.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_7.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteQueryMerchantFundMerchantIncomeRecordsAsync(this WechatTenpayClient client, Models.QueryMerchantFundMerchantIncomeRecordsRequest 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
+ .CreateRequest(request, HttpMethod.Get, "merchantfund", "merchant", "income-records")
+ .SetQueryParam("account_type", request.AccountType)
+ .SetQueryParam("date", request.DateString)
+ .SetQueryParam("limit", request.Limit);
+
+ if (request.Offset.HasValue)
+ flurlReq.SetQueryParam("offset", request.Offset);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// 异步调用 [GET] /merchantfund/partner/income-records 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_6.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteQueryMerchantFundPartnerIncomeRecordsAsync(this WechatTenpayClient client, Models.QueryMerchantFundPartnerIncomeRecordsRequest 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
+ .CreateRequest(request, HttpMethod.Get, "merchantfund", "partner", "income-records")
+ .SetQueryParam("sub_mchid", request.SubMerchantId)
+ .SetQueryParam("account_type", request.AccountType)
+ .SetQueryParam("date", request.DateString)
+ .SetQueryParam("limit", request.Limit);
+
+ if (request.Offset.HasValue)
+ flurlReq.SetQueryParam("offset", request.Offset);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, cancellationToken: cancellationToken);
+ }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundWithdrawExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundWithdrawExtensions.cs
index ea437c37..0a392486 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundWithdrawExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMerchantFundWithdrawExtensions.cs
@@ -74,6 +74,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 异步调用 [GET] /merchant/fund/withdraw/bill-type/{bill_type} 接口。
/// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_8_4.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter6_3.shtml
///
///
///
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecutePartnerTransferExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecutePartnerTransferExtensions.cs
new file mode 100644
index 00000000..9569caba
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecutePartnerTransferExtensions.cs
@@ -0,0 +1,133 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Flurl;
+using Flurl.Http;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
+{
+ ///
+ /// 为 提供服务商转账相关的 API 扩展方法。
+ ///
+ public static class WechatTenpayClientExecutePartnerTransferExtensions
+ {
+ #region Batches
+ ///
+ /// 异步调用 [POST] /partner-transfer/batches 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_1.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteCreatePartnerTransferBatchAsync(this WechatTenpayClient client, Models.CreatePartnerTransferBatchRequest 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
+ .CreateRequest(request, HttpMethod.Post, "partner-transfer", "batches");
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+ ///
+ /// 异步调用 [GET] /partner-transfer/batches/batch-id/{batch_id} 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_2.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetPartnerTransferBatchByBatchIdAsync(this WechatTenpayClient client, Models.GetPartnerTransferBatchByBatchIdRequest 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
+ .CreateRequest(request, HttpMethod.Get, "partner-transfer", "batches", "batch-id", request.BatchId)
+ .SetQueryParam("need_query_detail", request.RequireQueryDetail);
+
+ if (request.Offset.HasValue)
+ flurlReq.SetQueryParam("offset", request.Offset.Value);
+
+ if (request.Limit.HasValue)
+ flurlReq.SetQueryParam("limit", request.Limit.Value);
+
+ if (!string.IsNullOrEmpty(request.DetailStatus))
+ flurlReq.SetQueryParam("detail_status", request.DetailStatus);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// 异步调用 [GET] /partner-transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id} 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_3.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetPartnerTransferBatchDetailByDetailIdAsync(this WechatTenpayClient client, Models.GetPartnerTransferBatchDetailByDetailIdRequest 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
+ .CreateRequest(request, HttpMethod.Get, "partner-transfer", "batches", "batch-id", request.BatchId, "details", "detail-id", request.DetailId);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// 异步调用 [GET] /partner-transfer/batches/out-batch-no/{out_batch_no} 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_4.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetPartnerTransferBatchByOutBatchNumberAsync(this WechatTenpayClient client, Models.GetPartnerTransferBatchByOutBatchNumberRequest 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
+ .CreateRequest(request, HttpMethod.Get, "partner-transfer", "batches", "out-batch-no", request.OutBatchNumber)
+ .SetQueryParam("need_query_detail", request.RequireQueryDetail);
+
+ if (request.Offset.HasValue)
+ flurlReq.SetQueryParam("offset", request.Offset.Value);
+
+ if (request.Limit.HasValue)
+ flurlReq.SetQueryParam("limit", request.Limit.Value);
+
+ if (!string.IsNullOrEmpty(request.DetailStatus))
+ flurlReq.SetQueryParam("detail_status", request.DetailStatus);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// 异步调用 [GET] /partner-transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no} 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter3_5.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetPartnerTransferBatchDetailByOutDetailNumberAsync(this WechatTenpayClient client, Models.GetPartnerTransferBatchDetailByOutDetailNumberRequest 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
+ .CreateRequest(request, HttpMethod.Get, "partner-transfer", "batches", "out-batch-no", request.OutBatchNumber, "details", "out-detail-no", request.OutDetailNumber);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+ #endregion
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteTransferExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteTransferExtensions.cs
new file mode 100644
index 00000000..3ee45bee
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteTransferExtensions.cs
@@ -0,0 +1,223 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Flurl;
+using Flurl.Http;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
+{
+ ///
+ /// 为 提供转账相关的 API 扩展方法。
+ ///
+ public static class WechatTenpayClientExecuteTransferExtensions
+ {
+ #region Batches
+ ///
+ /// 异步调用 [POST] /transfer/batches 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_1.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteCreateTransferBatchAsync(this WechatTenpayClient client, Models.CreateTransferBatchRequest 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
+ .CreateRequest(request, HttpMethod.Post, "transfer", "batches");
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// 异步调用 [GET] /transfer/batches/batch-id/{batch_id} 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_2.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetTransferBatchByBatchIdAsync(this WechatTenpayClient client, Models.GetTransferBatchByBatchIdRequest 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
+ .CreateRequest(request, HttpMethod.Get, "transfer", "batches", "batch-id", request.BatchId)
+ .SetQueryParam("need_query_detail", request.RequireQueryDetail);
+
+ if (request.Offset.HasValue)
+ flurlReq.SetQueryParam("offset", request.Offset.Value);
+
+ if (request.Limit.HasValue)
+ flurlReq.SetQueryParam("limit", request.Limit.Value);
+
+ if (!string.IsNullOrEmpty(request.DetailStatus))
+ flurlReq.SetQueryParam("detail_status", request.DetailStatus);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// 异步调用 [GET] /transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id} 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_3.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetTransferBatchDetailByDetailIdAsync(this WechatTenpayClient client, Models.GetTransferBatchDetailByDetailIdRequest 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
+ .CreateRequest(request, HttpMethod.Get, "transfer", "batches", "batch-id", request.BatchId, "details", "detail-id", request.DetailId);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// 异步调用 [GET] /transfer/batches/out-batch-no/{out_batch_no} 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_4.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetTransferBatchByOutBatchNumberAsync(this WechatTenpayClient client, Models.GetTransferBatchByOutBatchNumberRequest 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
+ .CreateRequest(request, HttpMethod.Get, "transfer", "batches", "out-batch-no", request.OutBatchNumber)
+ .SetQueryParam("need_query_detail", request.RequireQueryDetail);
+
+ if (request.Offset.HasValue)
+ flurlReq.SetQueryParam("offset", request.Offset.Value);
+
+ if (request.Limit.HasValue)
+ flurlReq.SetQueryParam("limit", request.Limit.Value);
+
+ if (!string.IsNullOrEmpty(request.DetailStatus))
+ flurlReq.SetQueryParam("detail_status", request.DetailStatus);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// 异步调用 [GET] /transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no} 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter3_5.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetTransferBatchDetailByOutDetailNumberAsync(this WechatTenpayClient client, Models.GetTransferBatchDetailByOutDetailNumberRequest 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
+ .CreateRequest(request, HttpMethod.Get, "transfer", "batches", "out-batch-no", request.OutBatchNumber, "details", "out-detail-no", request.OutDetailNumber);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+ #endregion
+
+ #region BillReceipt
+ ///
+ /// 异步调用 [POST] /transfer/bill-receipt 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_1.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter4_1.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteCreateTransferBillReceiptAsync(this WechatTenpayClient client, Models.CreateTransferBillReceiptRequest 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
+ .CreateRequest(request, HttpMethod.Post, "transfer", "bill-receipt");
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// 异步调用 [GET] /transfer/bill-receipt/{out_batch_no} 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_2.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter4_2.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetTransferBillReceiptByOutBatchNumberAsync(this WechatTenpayClient client, Models.GetTransferBillReceiptByOutBatchNumberRequest 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
+ .CreateRequest(request, HttpMethod.Get, "transfer", "bill-receipt", request.OutBatchNumber);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+ #endregion
+
+ #region Detail
+ ///
+ /// 异步调用 [POST] /transfer-detail/electronic-receipts 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_4.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter4_4.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteCreateTransferDetailElectronicReceiptAsync(this WechatTenpayClient client, Models.CreateTransferDetailElectronicReceiptRequest 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
+ .CreateRequest(request, HttpMethod.Post, "transfer-detail", "electronic-receipts");
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+
+ ///
+ /// 异步调用 [GET] /transfer-detail/electronic-receipts 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer/chapter4_5.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transfer_partner/chapter4_5.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetTransferDetailElectronicReceiptByOutDetailNumberAsync(this WechatTenpayClient client, Models.GetTransferDetailElectronicReceiptByOutDetailNumberRequest 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
+ .CreateRequest(request, HttpMethod.Get, "transfer-detail", "electronic-receipts")
+ .SetQueryParam("accept_type", request.AcceptType)
+ .SetQueryParam("out_detail_no", request.OutDetailNumber);
+
+ if (!string.IsNullOrEmpty(request.OutBatchNumber))
+ flurlReq.SetQueryParam("out_batch_no", request.OutBatchNumber);
+
+ return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken);
+ }
+ #endregion
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseDecryptionExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseDecryptionExtensions.cs
index 3850c772..409a3dba 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseDecryptionExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseDecryptionExtensions.cs
@@ -11,13 +11,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
{
///
/// 解密响应中返回的敏感数据。该方法会改变传入的响应信息。
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_3.shtml
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_3.shtml
///
///
///
///
- public static Models.GetEcommerceApplymentByOutRequestNumberResponse DecryptResponseEncryptedData(this WechatTenpayClient client, Models.GetEcommerceApplymentByOutRequestNumberResponse response)
+ public static Models.GetEcommerceApplymentByOutRequestNumberResponse DecryptResponseEncryptedData(this WechatTenpayClient client, ref Models.GetEcommerceApplymentByOutRequestNumberResponse response)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (response == null) throw new ArgumentNullException(nameof(response));
@@ -73,13 +71,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 解密响应中返回的敏感数据。该方法会改变传入的响应信息。
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_3.shtml
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_3.shtml
///
///
///
///
- public static Models.GetEcommerceBillFundflowBillResponse DecryptResponseEncryptedData(this WechatTenpayClient client, Models.GetEcommerceBillFundflowBillResponse response)
+ public static Models.GetEcommerceBillFundflowBillResponse DecryptResponseEncryptedData(this WechatTenpayClient client, ref Models.GetEcommerceBillFundflowBillResponse response)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (response == null) throw new ArgumentNullException(nameof(response));
@@ -121,13 +117,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 解密响应中返回的敏感数据。该方法会改变传入的响应信息。
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_3.shtml
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_3.shtml
///
///
///
///
- public static Models.GetMerchantServiceComplaintByComplaintIdResponse DecryptResponseEncryptedData(this WechatTenpayClient client, Models.GetMerchantServiceComplaintByComplaintIdResponse response)
+ public static Models.GetMerchantServiceComplaintByComplaintIdResponse DecryptResponseEncryptedData(this WechatTenpayClient client, ref Models.GetMerchantServiceComplaintByComplaintIdResponse response)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (response == null) throw new ArgumentNullException(nameof(response));
@@ -161,13 +155,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 解密响应中返回的敏感数据。该方法会改变传入的响应信息。
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_3.shtml
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_3.shtml
///
///
///
///
- public static Models.QueryCertificatesResponse DecryptResponseEncryptedData(this WechatTenpayClient client, Models.QueryCertificatesResponse response)
+ public static Models.QueryCertificatesResponse DecryptResponseEncryptedData(this WechatTenpayClient client, ref Models.QueryCertificatesResponse response)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (response == null) throw new ArgumentNullException(nameof(response));
@@ -215,13 +207,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 解密响应中返回的敏感数据。该方法会改变传入的响应信息。
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_3.shtml
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_3.shtml
///
///
///
///
- public static Models.QueryMerchantServiceComplaintsResponse DecryptResponseEncryptedData(this WechatTenpayClient client, Models.QueryMerchantServiceComplaintsResponse response)
+ public static Models.QueryMerchantServiceComplaintsResponse DecryptResponseEncryptedData(this WechatTenpayClient client, ref Models.QueryMerchantServiceComplaintsResponse response)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (response == null) throw new ArgumentNullException(nameof(response));
@@ -263,13 +253,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 解密响应中返回的敏感数据。该方法会改变传入的响应信息。
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_3.shtml
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_3.shtml
///
///
///
///
- public static Models.QuerySmartGuidesResponse DecryptResponseEncryptedData(this WechatTenpayClient client, Models.QuerySmartGuidesResponse response)
+ public static Models.QuerySmartGuidesResponse DecryptResponseEncryptedData(this WechatTenpayClient client, ref Models.QuerySmartGuidesResponse response)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (response == null) throw new ArgumentNullException(nameof(response));
@@ -323,5 +311,145 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
return response;
}
+
+ ///
+ /// 解密响应中返回的敏感数据。该方法会改变传入的响应信息。
+ ///
+ ///
+ ///
+ ///
+ public static Models.GetTransferBatchDetailByOutDetailNumberResponse DecryptResponseEncryptedData(this WechatTenpayClient client, ref Models.GetTransferBatchDetailByOutDetailNumberResponse response)
+ {
+ if (client == null) throw new ArgumentNullException(nameof(client));
+ if (response == null) throw new ArgumentNullException(nameof(response));
+
+ if (string.IsNullOrEmpty(client.WechatMerchantCertPrivateKey))
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed, because of there is no merchant private key.");
+
+ if (!response.IsSuccessful())
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed, because of the response is not successful.");
+
+ if (!string.IsNullOrEmpty(response.UserName))
+ {
+ try
+ {
+ response.UserName = Utilities.RSAUtility.DecryptWithECB(
+ client.WechatMerchantCertPrivateKey,
+ response.UserName
+ );
+ }
+ catch (Exception ex)
+ {
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed.", ex);
+ }
+ }
+
+ return response;
+ }
+
+ ///
+ /// 解密响应中返回的敏感数据。该方法会改变传入的响应信息。
+ ///
+ ///
+ ///
+ ///
+ public static Models.GetTransferBatchDetailByDetailIdResponse DecryptResponseEncryptedData(this WechatTenpayClient client, ref Models.GetTransferBatchDetailByDetailIdResponse response)
+ {
+ if (client == null) throw new ArgumentNullException(nameof(client));
+ if (response == null) throw new ArgumentNullException(nameof(response));
+
+ if (string.IsNullOrEmpty(client.WechatMerchantCertPrivateKey))
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed, because of there is no merchant private key.");
+
+ if (!response.IsSuccessful())
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed, because of the response is not successful.");
+
+ if (!string.IsNullOrEmpty(response.UserName))
+ {
+ try
+ {
+ response.UserName = Utilities.RSAUtility.DecryptWithECB(
+ client.WechatMerchantCertPrivateKey,
+ response.UserName
+ );
+ }
+ catch (Exception ex)
+ {
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed.", ex);
+ }
+ }
+
+ return response;
+ }
+
+ ///
+ /// 解密响应中返回的敏感数据。该方法会改变传入的响应信息。
+ ///
+ ///
+ ///
+ ///
+ public static Models.GetPartnerTransferBatchDetailByOutDetailNumberResponse DecryptResponseEncryptedData(this WechatTenpayClient client, ref Models.GetPartnerTransferBatchDetailByOutDetailNumberResponse response)
+ {
+ if (client == null) throw new ArgumentNullException(nameof(client));
+ if (response == null) throw new ArgumentNullException(nameof(response));
+
+ if (string.IsNullOrEmpty(client.WechatMerchantCertPrivateKey))
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed, because of there is no merchant private key.");
+
+ if (!response.IsSuccessful())
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed, because of the response is not successful.");
+
+ if (!string.IsNullOrEmpty(response.UserName))
+ {
+ try
+ {
+ response.UserName = Utilities.RSAUtility.DecryptWithECB(
+ client.WechatMerchantCertPrivateKey,
+ response.UserName
+ );
+ }
+ catch (Exception ex)
+ {
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed.", ex);
+ }
+ }
+
+ return response;
+ }
+
+ ///
+ /// 解密响应中返回的敏感数据。该方法会改变传入的响应信息。
+ ///
+ ///
+ ///
+ ///
+ public static Models.GetPartnerTransferBatchDetailByDetailIdResponse DecryptResponseEncryptedData(this WechatTenpayClient client, ref Models.GetPartnerTransferBatchDetailByDetailIdResponse response)
+ {
+ if (client == null) throw new ArgumentNullException(nameof(client));
+ if (response == null) throw new ArgumentNullException(nameof(response));
+
+ if (string.IsNullOrEmpty(client.WechatMerchantCertPrivateKey))
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed, because of there is no merchant private key.");
+
+ if (!response.IsSuccessful())
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed, because of the response is not successful.");
+
+ if (!string.IsNullOrEmpty(response.UserName))
+ {
+ try
+ {
+ response.UserName = Utilities.RSAUtility.DecryptWithECB(
+ client.WechatMerchantCertPrivateKey,
+ response.UserName
+ );
+ }
+ catch (Exception ex)
+ {
+ throw new Exceptions.WechatTenpayResponseDecryptionException("Decrypt response failed.", ex);
+ }
+ }
+
+ return response;
+ }
}
}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs
new file mode 100644
index 00000000..0b45bf7c
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Text;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
+{
+ ///
+ /// 为 提供响应签名验证的扩展方法。
+ ///
+ public static class WechatTenpayClientResponseVerificationExtensions
+ {
+ ///
+ /// 验证响应签名。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_1.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static bool VerifyResponseSignature(this WechatTenpayClient client, TResponse response)
+ where TResponse : WechatTenpayResponse
+ {
+ if (client == null) throw new ArgumentNullException(nameof(client));
+ if (response == null) throw new ArgumentNullException(nameof(response));
+
+ if (client.WechatCertificateStorer == null)
+ {
+ throw new Exceptions.WechatTenpayResponseVerificationException($"You must set an instance of `{nameof(Settings.ICertificateStorer)}` at first.");
+ }
+ else
+ {
+ if (response.WechatpayCertSerialNumber == null)
+ throw new Exceptions.WechatTenpayResponseVerificationException("Cannot read the serial number in headers of this response.");
+
+ string? certificate = client.WechatCertificateStorer.Get(response.WechatpayCertSerialNumber);
+ if (certificate == null)
+ throw new Exceptions.WechatTenpayResponseVerificationException("Cannot get certificate by the serial number, may not be stored.");
+
+ string? publicKey = null;
+ try
+ {
+ publicKey = Utilities.RSAUtility.ExportPublicKey(certificate);
+ }
+ catch (Exception ex)
+ {
+ throw new Exceptions.WechatTenpayResponseVerificationException("Cannot get public key of the certificate, may not be a valid certificate data.", ex);
+ }
+
+ try
+ {
+ return Utilities.RSAUtility.VerifyWithSHA256(
+ publicKey: publicKey,
+ plainText: GetPlainTextForSignature(response),
+ signature: response.WechatpaySignature
+ );
+ }
+ catch (Exception ex)
+ {
+ throw new Exceptions.WechatTenpayResponseVerificationException("Verify response signature failed.", ex);
+ }
+ }
+ }
+
+ private static string GetPlainTextForSignature(WechatTenpayResponse response)
+ {
+ string timestamp = response.WechatpayTimestamp;
+ string nonce = response.WechatpayNonce;
+ string body = Encoding.UTF8.GetString(response.RawBytes);
+ return $"{timestamp}\n{nonce}\n{body}\n";
+ }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerifyExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerifyExtensions.cs
deleted file mode 100644
index 2e86dd8d..00000000
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerifyExtensions.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System;
-using System.Text;
-
-namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
-{
- ///
- /// 为 提供响应签名验证的扩展方法。
- ///
- public static class WechatTenpayClientResponseVerifyExtensions
- {
- ///
- /// 验证响应签名(使用微信支付平台证书公钥)。
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_1.shtml
- ///
- ///
- ///
- ///
- ///
- ///
- public static bool VerifyResponseSignature(this WechatTenpayClient client, TResponse response, string publicKey)
- where TResponse : WechatTenpayResponse
- {
- if (client == null) throw new ArgumentNullException(nameof(client));
- if (response == null) throw new ArgumentNullException(nameof(response));
- if (string.IsNullOrEmpty(publicKey)) throw new ArgumentNullException(publicKey);
-
- try
- {
- return Utilities.RSAUtility.VerifyWithSHA256(
- publicKey: publicKey,
- plainText: GetPlainTextForSignature(response),
- signature: response.WechatpaySignature
- );
- }
- catch (Exception ex)
- {
- throw new Exceptions.WechatTenpayResponseVerificationException("Verify response signature failed.", ex);
- }
- }
-
- ///
- /// 验证响应签名(使用微信支付平台证书)。
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml
- /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_1.shtml
- ///
- ///
- ///
- ///
- ///
- ///
- public static bool VerifyResponseSignatureByCertificate(this WechatTenpayClient client, TResponse response, string certificate)
- where TResponse : WechatTenpayResponse
- {
- if (client == null) throw new ArgumentNullException(nameof(client));
- if (response == null) throw new ArgumentNullException(nameof(response));
- if (string.IsNullOrEmpty(certificate)) throw new ArgumentNullException(certificate);
-
- try
- {
- return Utilities.RSAUtility.VerifyWithSHA256ByCertificate(
- certificate: certificate,
- plainText: GetPlainTextForSignature(response),
- signature: response.WechatpaySignature
- );
- }
- catch (Exception ex)
- {
- throw new Exceptions.WechatTenpayResponseVerificationException("Verify response signature failed.", ex);
- }
- }
-
- private static string GetPlainTextForSignature(WechatTenpayResponse response)
- {
- string timestamp = response.WechatpayTimestamp;
- string nonce = response.WechatpayNonce;
- string body = Encoding.UTF8.GetString(response.RawBytes);
- return $"{timestamp}\n{nonce}\n{body}\n";
- }
- }
-}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Interceptors/WechatTenpaySignInterceptor.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Interceptors/WechatTenpaySignInterceptor.cs
index 6f8e101e..2d426685 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Interceptors/WechatTenpaySignInterceptor.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Interceptors/WechatTenpaySignInterceptor.cs
@@ -53,7 +53,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Interceptors
switch (_scheme)
{
- case WechatTenpayAuthSchemes.WECHATPAY2_SHA256_RSA2048:
+ case Constants.SignAlgorithms.WECHATPAY2_SHA256_RSA2048:
{
try
{
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/CreateApplyForSubMerchantApplymentRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/CreateApplyForSubMerchantApplymentRequest.cs
index 12dee55a..4266e544 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/CreateApplyForSubMerchantApplymentRequest.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/CreateApplyForSubMerchantApplymentRequest.cs
@@ -738,7 +738,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
public string? BankBranchId { get; set; }
///
- /// 获取或设置开户开户银行全称(含支行)。与字段 二选一。
+ /// 获取或设置开户银行全称(含支行)。与字段 二选一。
///
[Newtonsoft.Json.JsonProperty("bank_name")]
[System.Text.Json.Serialization.JsonPropertyName("bank_name")]
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/Settlement/GetApplyForSubMerchantSettlementResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/Settlement/GetApplyForSubMerchantSettlementResponse.cs
index 6616834c..25a66fbc 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/Settlement/GetApplyForSubMerchantSettlementResponse.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/Settlement/GetApplyForSubMerchantSettlementResponse.cs
@@ -44,7 +44,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
public string? BankBranchId { get; set; }
///
- /// 获取或设置开户开户银行全称(含支行)。
+ /// 获取或设置开户银行全称(含支行)。
///
[Newtonsoft.Json.JsonProperty("bank_name")]
[System.Text.Json.Serialization.JsonPropertyName("bank_name")]
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/Settlement/ModifyApplyForSubMerchantSettlementRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/Settlement/ModifyApplyForSubMerchantSettlementRequest.cs
index cbaa80ff..a20b32c7 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/Settlement/ModifyApplyForSubMerchantSettlementRequest.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Apply4SubMerchant/Settlement/ModifyApplyForSubMerchantSettlementRequest.cs
@@ -51,7 +51,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
public string? BankBranchId { get; set; }
///
- /// 获取或设置开户开户银行全称(含支行)。与字段 二选一。
+ /// 获取或设置开户银行全称(含支行)。与字段 二选一。
///
[Newtonsoft.Json.JsonProperty("bank_name")]
[System.Text.Json.Serialization.JsonPropertyName("bank_name")]
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/EcommerceApplyments/CreateEcommerceApplymentRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/EcommerceApplyments/CreateEcommerceApplymentRequest.cs
index acea858f..3f040025 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/EcommerceApplyments/CreateEcommerceApplymentRequest.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/EcommerceApplyments/CreateEcommerceApplymentRequest.cs
@@ -231,7 +231,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
public string? BankBranchId { get; set; }
///
- /// 获取或设置开户开户银行全称(含支行)。与字段 二选一。
+ /// 获取或设置开户银行全称(含支行)。与字段 二选一。
///
[Newtonsoft.Json.JsonProperty("bank_name")]
[System.Text.Json.Serialization.JsonPropertyName("bank_name")]
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/EcommerceFundWithdraw/GetEcommerceFundWithdrawByOutRequestNumberResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/EcommerceFundWithdraw/GetEcommerceFundWithdrawByOutRequestNumberResponse.cs
index 5ec37381..4c39b128 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/EcommerceFundWithdraw/GetEcommerceFundWithdrawByOutRequestNumberResponse.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/EcommerceFundWithdraw/GetEcommerceFundWithdrawByOutRequestNumberResponse.cs
@@ -86,7 +86,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
public string AccountBank { get; set; } = default!;
///
- /// 获取或设置开户开户银行全称(含支行)。
+ /// 获取或设置开户银行全称(含支行)。
///
[Newtonsoft.Json.JsonProperty("bank_name")]
[System.Text.Json.Serialization.JsonPropertyName("bank_name")]
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsRequest.cs
new file mode 100644
index 00000000..687b151d
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsRequest.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /merchantfund/merchant/income-records 接口的请求。
+ ///
+ public class QueryMerchantFundMerchantIncomeRecordsRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置账户类型。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string AccountType { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置日期(格式:yyyy-MM-dd)。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string DateString { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置分页开始位置。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public int? Offset { get; set; }
+
+ ///
+ /// 获取或设置分页每页数量。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public int Limit { get; set; } = 10;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsResponse.cs
new file mode 100644
index 00000000..2d2aea13
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsResponse.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /merchantfund/merchant/income-records 接口的响应。
+ ///
+ public class QueryMerchantFundMerchantIncomeRecordsResponse : WechatTenpayResponse
+ {
+ public static class Types
+ {
+ public class IncomeRecord
+ {
+ ///
+ /// 获取或设置微信商户号。
+ ///
+ [Newtonsoft.Json.JsonProperty("mchid")]
+ [System.Text.Json.Serialization.JsonPropertyName("mchid")]
+ public string MerchantId { get; set; } = default!;
+
+ ///
+ /// 获取或设置账户类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("account_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("account_type")]
+ public string AccountType { get; set; } = default!;
+
+ ///
+ /// 获取或设置银行来账类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("income_record_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("income_record_type")]
+ public string IncomeRecordType { get; set; } = default!;
+
+ ///
+ /// 获取或设置银行来账微信单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("income_record_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("income_record_id")]
+ public string IncomeRecordId { get; set; } = default!;
+
+ ///
+ /// 获取或设置银行来账金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("amount")]
+ public int Amount { get; set; }
+
+ ///
+ /// 获取或设置企业微信的员工工号。
+ ///
+ [Newtonsoft.Json.JsonProperty("success_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("success_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ public DateTimeOffset SuccessTime { get; set; }
+
+ ///
+ /// 获取或设置付款方银行名称。
+ ///
+ [Newtonsoft.Json.JsonProperty("bank_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("bank_name")]
+ public string BankName { get; set; } = default!;
+
+ ///
+ /// 获取或设置付款方银行户名。
+ ///
+ [Newtonsoft.Json.JsonProperty("bank_account_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("bank_account_name")]
+ public string BankAccountName { get; set; } = default!;
+
+ ///
+ /// 获取或设置付款方银行卡号。
+ ///
+ [Newtonsoft.Json.JsonProperty("bank_account_number")]
+ [System.Text.Json.Serialization.JsonPropertyName("bank_account_number")]
+ public string BankAccountNumber { get; set; } = default!;
+ }
+ }
+
+ ///
+ /// 获取或设置银行来账记录列表。
+ ///
+ [Newtonsoft.Json.JsonProperty("data")]
+ [System.Text.Json.Serialization.JsonPropertyName("data")]
+ public Types.IncomeRecord[]? IncomeRecordList { get; set; }
+
+ ///
+ /// 获取或设置分页大小。
+ ///
+ [Newtonsoft.Json.JsonProperty("limit")]
+ [System.Text.Json.Serialization.JsonPropertyName("limit")]
+ public int Limit { get; set; }
+
+ ///
+ /// 获取或设置分页开始位置。
+ ///
+ [Newtonsoft.Json.JsonProperty("offset")]
+ [System.Text.Json.Serialization.JsonPropertyName("offset")]
+ public int Offset { get; set; }
+
+ ///
+ /// 获取或设置银行来账记录总数。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_count")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_count")]
+ public int TotalCount { get; set; }
+
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsRequest.cs
new file mode 100644
index 00000000..21fa56c2
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsRequest.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /merchantfund/partner/income-records 接口的请求。
+ ///
+ public class QueryMerchantFundPartnerIncomeRecordsRequest : QueryMerchantFundMerchantIncomeRecordsRequest
+ {
+ ///
+ /// 获取或设置特约商户号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string SubMerchantId { get; set; } = string.Empty;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsResponse.cs
new file mode 100644
index 00000000..82665c0f
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsResponse.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /merchantfund/partner/income-records 接口的响应。
+ ///
+ public class QueryMerchantFundPartnerIncomeRecordsResponse : WechatTenpayResponse
+ {
+ public static class Types
+ {
+ public class IncomeRecord
+ {
+ ///
+ /// 获取或设置特约商户号。
+ ///
+ [Newtonsoft.Json.JsonProperty("sub_mchid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sub_mchid")]
+ public string SubMerchantId { get; set; } = default!;
+
+ ///
+ /// 获取或设置账户类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("account_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("account_type")]
+ public string AccountType { get; set; } = default!;
+
+ ///
+ /// 获取或设置银行来账类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("income_record_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("income_record_type")]
+ public string IncomeRecordType { get; set; } = default!;
+
+ ///
+ /// 获取或设置银行来账微信单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("income_record_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("income_record_id")]
+ public string IncomeRecordId { get; set; } = default!;
+
+ ///
+ /// 获取或设置银行来账金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("amount")]
+ public int Amount { get; set; }
+
+ ///
+ /// 获取或设置企业微信的员工工号。
+ ///
+ [Newtonsoft.Json.JsonProperty("success_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("success_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ public DateTimeOffset SuccessTime { get; set; }
+
+ ///
+ /// 获取或设置付款方银行名称。
+ ///
+ [Newtonsoft.Json.JsonProperty("bank_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("bank_name")]
+ public string BankName { get; set; } = default!;
+
+ ///
+ /// 获取或设置付款方银行户名。
+ ///
+ [Newtonsoft.Json.JsonProperty("bank_account_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("bank_account_name")]
+ public string BankAccountName { get; set; } = default!;
+
+ ///
+ /// 获取或设置付款方银行卡号。
+ ///
+ [Newtonsoft.Json.JsonProperty("bank_account_number")]
+ [System.Text.Json.Serialization.JsonPropertyName("bank_account_number")]
+ public string BankAccountNumber { get; set; } = default!;
+ }
+ }
+
+ ///
+ /// 获取或设置银行来账记录列表。
+ ///
+ [Newtonsoft.Json.JsonProperty("data")]
+ [System.Text.Json.Serialization.JsonPropertyName("data")]
+ public Types.IncomeRecord[]? IncomeRecordList { get; set; }
+
+ ///
+ /// 获取或设置分页大小。
+ ///
+ [Newtonsoft.Json.JsonProperty("limit")]
+ [System.Text.Json.Serialization.JsonPropertyName("limit")]
+ public int Limit { get; set; }
+
+ ///
+ /// 获取或设置分页开始位置。
+ ///
+ [Newtonsoft.Json.JsonProperty("offset")]
+ [System.Text.Json.Serialization.JsonPropertyName("offset")]
+ public int Offset { get; set; }
+
+ ///
+ /// 获取或设置银行来账记录总数。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_count")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_count")]
+ public int TotalCount { get; set; }
+
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundWithdraw/GetMerchantFundWithdrawByOutRequestNumberResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundWithdraw/GetMerchantFundWithdrawByOutRequestNumberResponse.cs
index 1568c539..03b7dc3f 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundWithdraw/GetMerchantFundWithdrawByOutRequestNumberResponse.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MerchantFundWithdraw/GetMerchantFundWithdrawByOutRequestNumberResponse.cs
@@ -72,7 +72,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
public string AccountBank { get; set; } = default!;
///
- /// 获取或设置开户开户银行全称(含支行)。
+ /// 获取或设置开户银行全称(含支行)。
///
[Newtonsoft.Json.JsonProperty("bank_name")]
[System.Text.Json.Serialization.JsonPropertyName("bank_name")]
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/CreatePartnerTransferBatchRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/CreatePartnerTransferBatchRequest.cs
new file mode 100644
index 00000000..82d43a87
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/CreatePartnerTransferBatchRequest.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [POST] /partner-transfer/batches 接口的请求。
+ ///
+ public class CreatePartnerTransferBatchRequest : WechatTenpayRequest
+ {
+ public static class Types
+ {
+ public class TransferDetail : CreateTransferBatchRequest.Types.TransferDetail
+ {
+ }
+ }
+
+ ///
+ /// 获取或设置特约商户号。
+ ///
+ [Newtonsoft.Json.JsonProperty("sub_mchid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sub_mchid")]
+ public string SubMerchantId { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置服务商 AppId。
+ ///
+ [Newtonsoft.Json.JsonProperty("sp_appid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sp_appid")]
+ public string? AppId { get; set; }
+
+ ///
+ /// 获取或设置特约商户 AppId。
+ ///
+ [Newtonsoft.Json.JsonProperty("sub_appid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sub_appid")]
+ public string? SubAppId { get; set; }
+
+ ///
+ /// 获取或设置特约商户授权类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("authorization_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("authorization_type")]
+ public string AuthorizationType { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string OutBatchNumber { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置批次名称。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_name")]
+ public string BatchName { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置批次备注。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_remark")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_remark")]
+ public string BatchRemark { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置转账总金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_amount")]
+ public int TotalAmount { get; set; }
+
+ ///
+ /// 获取或设置转账总笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_num")]
+ public int TotalNumber { get; set; }
+
+ ///
+ /// 获取或设置转账明细列表。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_detail_list")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_detail_list")]
+ public IList TransferDetailList { get; set; } = new List();
+
+ ///
+ /// 获取或设置转账用途。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_purpose")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_purpose")]
+ public string? TransferPurpose { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/CreatePartnerTransferBatchResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/CreatePartnerTransferBatchResponse.cs
new file mode 100644
index 00000000..1e9b5574
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/CreatePartnerTransferBatchResponse.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [POST] /partner-transfer/batches 接口的响应。
+ ///
+ public class CreatePartnerTransferBatchResponse : CreateTransferBatchResponse
+ {
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdRequest.cs
new file mode 100644
index 00000000..6e8cce4d
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdRequest.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /partner-transfer/batches/batch-id/{batch_id} 接口的请求。
+ ///
+ public class GetPartnerTransferBatchByBatchIdRequest : GetTransferBatchByBatchIdRequest
+ {
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdResponse.cs
new file mode 100644
index 00000000..6dca7119
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdResponse.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /partner-transfer/batches/batch-id/{batch_id} 接口的响应。
+ ///
+ public class GetPartnerTransferBatchByBatchIdResponse : WechatTenpayResponse
+ {
+ public static class Types
+ {
+ public class TransferDetail : GetPartnerTransferBatchByOutBatchNumberResponse.Types.TransferDetail
+ {
+ }
+ }
+
+ ///
+ /// 获取或设置服务商商户号。
+ ///
+ [Newtonsoft.Json.JsonProperty("sp_mchid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sp_mchid")]
+ public string MerchantId { get; set; } = default!;
+
+ ///
+ /// 获取或设置特约商户号。
+ ///
+ [Newtonsoft.Json.JsonProperty("sub_mchid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sub_mchid")]
+ public string SubMerchantId { get; set; } = default!;
+
+ ///
+ /// 获取或设置服务商 AppId。
+ ///
+ [Newtonsoft.Json.JsonProperty("sp_appid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sp_appid")]
+ public string? AppId { get; set; }
+
+ ///
+ /// 获取或设置特约商户 AppId。
+ ///
+ [Newtonsoft.Json.JsonProperty("sub_appid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sub_appid")]
+ public string? SubAppId { get; set; }
+
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string OutBatchNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置微信批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_id")]
+ public string BatchId { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次状态。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_status")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_status")]
+ public string BatchStatus { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_type")]
+ public string BatchType { get; set; } = default!;
+
+ ///
+ /// 获取或设置特约商户授权类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("authorization_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("authorization_type")]
+ public string AuthorizationType { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次名称。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_name")]
+ public string BatchName { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次备注。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_remark")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_remark")]
+ public string BatchRemark { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次关闭原因。
+ ///
+ [Newtonsoft.Json.JsonProperty("close_reason")]
+ [System.Text.Json.Serialization.JsonPropertyName("close_reason")]
+ public string? CloseReason { get; set; }
+
+ ///
+ /// 获取或设置转账总金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_amount")]
+ public int TotalAmount { get; set; }
+
+ ///
+ /// 获取或设置转账总笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_num")]
+ public int TotalNumber { get; set; }
+
+ ///
+ /// 获取或设置批次创建时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("create_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("create_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ public DateTimeOffset CreateTime { get; set; }
+
+ ///
+ /// 获取或设置批次更新时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("update_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339NullableDateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("update_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339NullableDateTimeOffsetConverter))]
+ public DateTimeOffset? UpdateTime { get; set; }
+
+ ///
+ /// 获取或设置转账成功金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("success_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("success_amount")]
+ public int SuccessAmount { get; set; }
+
+ ///
+ /// 获取或设置转账成功笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("success_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("success_num")]
+ public int SuccessNumber { get; set; }
+
+ ///
+ /// 获取或设置转账失败金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("fail_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("fail_amount")]
+ public int FailAmount { get; set; }
+
+ ///
+ /// 获取或设置转账失败笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("fail_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("fail_num")]
+ public int FailNumber { get; set; }
+
+ ///
+ /// 获取或设置转账用途。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_purpose")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_purpose")]
+ public string? TransferPurpose { get; set; }
+
+ ///
+ /// 获取或设置转账明细单列表。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_detail_list")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_detail_list")]
+ public Types.TransferDetail[]? TransferDetailList { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberRequest.cs
new file mode 100644
index 00000000..5fca88fa
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberRequest.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /partner-transfer/batches/out-batch-no/{out_batch_no} 接口的请求。
+ ///
+ public class GetPartnerTransferBatchByOutBatchNumberRequest : GetTransferBatchByOutBatchNumberRequest
+ {
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberResponse.cs
new file mode 100644
index 00000000..66cd54a8
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberResponse.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /partner-transfer/batches/out-batch-no/{out_batch_no} 接口的响应。
+ ///
+ public class GetPartnerTransferBatchByOutBatchNumberResponse : WechatTenpayResponse
+ {
+ public static class Types
+ {
+ public class TransferDetail : GetTransferBatchByOutBatchNumberResponse.Types.TransferDetail
+ {
+ }
+ }
+
+ ///
+ /// 获取或设置服务商商户号。
+ ///
+ [Newtonsoft.Json.JsonProperty("sp_mchid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sp_mchid")]
+ public string MerchantId { get; set; } = default!;
+
+ ///
+ /// 获取或设置特约商户号。
+ ///
+ [Newtonsoft.Json.JsonProperty("sub_mchid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sub_mchid")]
+ public string SubMerchantId { get; set; } = default!;
+
+ ///
+ /// 获取或设置服务商 AppId。
+ ///
+ [Newtonsoft.Json.JsonProperty("sp_appid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sp_appid")]
+ public string? AppId { get; set; }
+
+ ///
+ /// 获取或设置特约商户 AppId。
+ ///
+ [Newtonsoft.Json.JsonProperty("sub_appid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sub_appid")]
+ public string? SubAppId { get; set; }
+
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string OutBatchNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置微信批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_id")]
+ public string BatchId { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次状态。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_status")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_status")]
+ public string BatchStatus { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_type")]
+ public string BatchType { get; set; } = default!;
+
+ ///
+ /// 获取或设置特约商户授权类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("authorization_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("authorization_type")]
+ public string AuthorizationType { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次名称。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_name")]
+ public string BatchName { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次备注。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_remark")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_remark")]
+ public string BatchRemark { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次关闭原因。
+ ///
+ [Newtonsoft.Json.JsonProperty("close_reason")]
+ [System.Text.Json.Serialization.JsonPropertyName("close_reason")]
+ public string? CloseReason { get; set; }
+
+ ///
+ /// 获取或设置转账总金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_amount")]
+ public int TotalAmount { get; set; }
+
+ ///
+ /// 获取或设置转账总笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_num")]
+ public int TotalNumber { get; set; }
+
+ ///
+ /// 获取或设置批次创建时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("create_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("create_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ public DateTimeOffset CreateTime { get; set; }
+
+ ///
+ /// 获取或设置批次更新时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("update_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339NullableDateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("update_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339NullableDateTimeOffsetConverter))]
+ public DateTimeOffset? UpdateTime { get; set; }
+
+ ///
+ /// 获取或设置转账成功金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("success_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("success_amount")]
+ public int SuccessAmount { get; set; }
+
+ ///
+ /// 获取或设置转账成功笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("success_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("success_num")]
+ public int SuccessNumber { get; set; }
+
+ ///
+ /// 获取或设置转账失败金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("fail_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("fail_amount")]
+ public int FailAmount { get; set; }
+
+ ///
+ /// 获取或设置转账失败笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("fail_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("fail_num")]
+ public int FailNumber { get; set; }
+
+ ///
+ /// 获取或设置转账用途。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_purpose")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_purpose")]
+ public string? TransferPurpose { get; set; }
+
+ ///
+ /// 获取或设置转账明细单列表。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_detail_list")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_detail_list")]
+ public Types.TransferDetail[]? TransferDetailList { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdRequest.cs
new file mode 100644
index 00000000..d2704d35
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdRequest.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /partner-transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id} 接口的请求。
+ ///
+ public class GetPartnerTransferBatchDetailByDetailIdRequest : GetTransferBatchDetailByDetailIdRequest
+ {
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdResponse.cs
new file mode 100644
index 00000000..c852614b
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdResponse.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /partner-transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id} 接口的响应。
+ ///
+ public class GetPartnerTransferBatchDetailByDetailIdResponse : GetPartnerTransferBatchDetailByOutDetailNumberResponse
+ {
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberRequest.cs
new file mode 100644
index 00000000..b8fc89bf
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberRequest.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /partner-transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no} 接口的请求。
+ ///
+ public class GetPartnerTransferBatchDetailByOutDetailNumberRequest : GetTransferBatchDetailByOutDetailNumberRequest
+ {
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberResponse.cs
new file mode 100644
index 00000000..f0e993b8
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberResponse.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /partner-transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no} 接口的响应。
+ ///
+ public class GetPartnerTransferBatchDetailByOutDetailNumberResponse : GetTransferBatchDetailByOutDetailNumberResponse
+ {
+ ///
+ /// 获取或设置服务商商户号。
+ ///
+ [Newtonsoft.Json.JsonProperty("sp_mchid")]
+ [System.Text.Json.Serialization.JsonPropertyName("sp_mchid")]
+ public string MerchantId { get; set; } = default!;
+
+ ///
+ /// 获取或设置收款用户姓名(需使用商户私钥解密)。
+ ///
+ [Newtonsoft.Json.JsonProperty("username")]
+ [System.Text.Json.Serialization.JsonPropertyName("username")]
+ public override string UserName { get; set; } = default!;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/CreateTransferBatchRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/CreateTransferBatchRequest.cs
new file mode 100644
index 00000000..52be9883
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/CreateTransferBatchRequest.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [POST] /transfer/batches 接口的请求。
+ ///
+ public class CreateTransferBatchRequest : WechatTenpayRequest
+ {
+ public static class Types
+ {
+ public class TransferDetail
+ {
+ ///
+ /// 获取或设置商户明细单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_detail_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_detail_no")]
+ public string OutDetailNumber { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置转账金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_amount")]
+ public int TransferAmount { get; set; }
+
+ ///
+ /// 获取或设置转账备注。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_remark")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_remark")]
+ public string TransferRemark { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置收款用户 OpenId。
+ ///
+ [Newtonsoft.Json.JsonProperty("openid")]
+ [System.Text.Json.Serialization.JsonPropertyName("openid")]
+ public string OpenId { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置收款用户姓名(需使用微信支付平台公钥加密)。
+ ///
+ [Newtonsoft.Json.JsonProperty("user_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("user_name")]
+ public string UserName { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置收款用户身份证号(需使用微信支付平台公钥加密)。
+ ///
+ [Newtonsoft.Json.JsonProperty("user_id_card")]
+ [System.Text.Json.Serialization.JsonPropertyName("user_id_card")]
+ public string UserIdCardNumber { get; set; } = string.Empty;
+ }
+ }
+
+ ///
+ /// 获取或设置微信 AppId。
+ ///
+ [Newtonsoft.Json.JsonProperty("appid")]
+ [System.Text.Json.Serialization.JsonPropertyName("appid")]
+ public string AppId { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string OutBatchNumber { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置批次名称。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_name")]
+ public string BatchName { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置批次备注。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_remark")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_remark")]
+ public string BatchRemark { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置转账总金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_amount")]
+ public int TotalAmount { get; set; }
+
+ ///
+ /// 获取或设置转账总笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_num")]
+ public int TotalNumber { get; set; }
+
+ ///
+ /// 获取或设置转账明细列表。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_detail_list")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_detail_list")]
+ public IList TransferDetailList { get; set; } = new List();
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/CreateTransferBatchResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/CreateTransferBatchResponse.cs
new file mode 100644
index 00000000..ed3cf0c8
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/CreateTransferBatchResponse.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [POST] /transfer/batches 接口的响应。
+ ///
+ public class CreateTransferBatchResponse : WechatTenpayResponse
+ {
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string OutBatchNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置微信批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_id")]
+ public string BatchId { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次创建时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("create_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("create_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ public DateTimeOffset CreateTime { get; set; } = default!;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByBatchIdRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByBatchIdRequest.cs
new file mode 100644
index 00000000..762c6d6a
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByBatchIdRequest.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer/batches/batch-id/{batch_id} 接口的请求。
+ ///
+ public class GetTransferBatchByBatchIdRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置微信批次单号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string BatchId { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置是否查询转账明细单。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public bool RequireQueryDetail { get; set; }
+
+ ///
+ /// 获取或设置分页开始位置。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public int? Offset { get; set; }
+
+ ///
+ /// 获取或设置分页每页数量。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public int? Limit { get; set; }
+
+ ///
+ /// 获取或设置明细状态。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string? DetailStatus { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByBatchIdResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByBatchIdResponse.cs
new file mode 100644
index 00000000..17d273e2
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByBatchIdResponse.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer/batches/batch-id/{batch_id} 接口的响应。
+ ///
+ public class GetTransferBatchByBatchIdResponse : WechatTenpayResponse
+ {
+ public static class Types
+ {
+ public class TransferBatch : GetTransferBatchByOutBatchNumberResponse.Types.TransferBatch
+ {
+ }
+
+ public class TransferDetail : GetTransferBatchByOutBatchNumberResponse.Types.TransferDetail
+ {
+ }
+ }
+
+ ///
+ /// 获取或设置转账批次单信息。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_batch")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_batch")]
+ public Types.TransferBatch TransferBatch { get; set; } = default!;
+
+ ///
+ /// 获取或设置转账明细单列表。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_detail_list")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_detail_list")]
+ public Types.TransferDetail[]? TransferDetailList { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByOutBatchNumberRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByOutBatchNumberRequest.cs
new file mode 100644
index 00000000..b2e8dace
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByOutBatchNumberRequest.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer/batches/out-batch-no/{out_batch_no} 接口的请求。
+ ///
+ public class GetTransferBatchByOutBatchNumberRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string OutBatchNumber { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置是否查询转账明细单。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public bool RequireQueryDetail { get; set; }
+
+ ///
+ /// 获取或设置分页开始位置。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public int? Offset { get; set; }
+
+ ///
+ /// 获取或设置分页每页数量。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public int? Limit { get; set; }
+
+ ///
+ /// 获取或设置明细状态。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string? DetailStatus { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByOutBatchNumberResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByOutBatchNumberResponse.cs
new file mode 100644
index 00000000..56c18134
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchByOutBatchNumberResponse.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer/batches/out-batch-no/{out_batch_no} 接口的响应。
+ ///
+ public class GetTransferBatchByOutBatchNumberResponse : WechatTenpayResponse
+ {
+ public static class Types
+ {
+ public class TransferBatch
+ {
+ ///
+ /// 获取或设置微信商户号。
+ ///
+ [Newtonsoft.Json.JsonProperty("mchid")]
+ [System.Text.Json.Serialization.JsonPropertyName("mchid")]
+ public string MerchantId { get; set; } = default!;
+
+ ///
+ /// 获取或设置微信 AppId。
+ ///
+ [Newtonsoft.Json.JsonProperty("appid")]
+ [System.Text.Json.Serialization.JsonPropertyName("appid")]
+ public string AppId { get; set; } = default!;
+
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string OutBatchNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置微信批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_id")]
+ public string BatchId { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次状态。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_status")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_status")]
+ public string BatchStatus { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_type")]
+ public string BatchType { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次名称。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_name")]
+ public string BatchName { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次备注。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_remark")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_remark")]
+ public string BatchRemark { get; set; } = default!;
+
+ ///
+ /// 获取或设置批次关闭原因。
+ ///
+ [Newtonsoft.Json.JsonProperty("close_reason")]
+ [System.Text.Json.Serialization.JsonPropertyName("close_reason")]
+ public string? CloseReason { get; set; }
+
+ ///
+ /// 获取或设置转账总金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_amount")]
+ public int TotalAmount { get; set; }
+
+ ///
+ /// 获取或设置转账总笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("total_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("total_num")]
+ public int TotalNumber { get; set; }
+
+ ///
+ /// 获取或设置批次创建时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("create_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("create_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ public DateTimeOffset CreateTime { get; set; }
+
+ ///
+ /// 获取或设置批次更新时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("update_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339NullableDateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("update_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339NullableDateTimeOffsetConverter))]
+ public DateTimeOffset? UpdateTime { get; set; }
+
+ ///
+ /// 获取或设置转账成功金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("success_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("success_amount")]
+ public int SuccessAmount { get; set; }
+
+ ///
+ /// 获取或设置转账成功笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("success_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("success_num")]
+ public int SuccessNumber { get; set; }
+
+ ///
+ /// 获取或设置转账失败金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("fail_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("fail_amount")]
+ public int FailAmount { get; set; }
+
+ ///
+ /// 获取或设置转账失败笔数。
+ ///
+ [Newtonsoft.Json.JsonProperty("fail_num")]
+ [System.Text.Json.Serialization.JsonPropertyName("fail_num")]
+ public int FailNumber { get; set; }
+ }
+
+ public class TransferDetail
+ {
+ ///
+ /// 获取或设置商户明细单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_detail_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_detail_no")]
+ public string OutDetailNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置微信明细单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("detail_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("detail_id")]
+ public string DetailId { get; set; } = default!;
+
+ ///
+ /// 获取或设置明细状态。
+ ///
+ [Newtonsoft.Json.JsonProperty("detail_status")]
+ [System.Text.Json.Serialization.JsonPropertyName("detail_status")]
+ public string DetailStatus { get; set; } = default!;
+ }
+ }
+
+ ///
+ /// 获取或设置转账批次单信息。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_batch")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_batch")]
+ public Types.TransferBatch TransferBatch { get; set; } = default!;
+
+ ///
+ /// 获取或设置转账明细单列表。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_detail_list")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_detail_list")]
+ public Types.TransferDetail[]? TransferDetailList { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByDetailIdRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByDetailIdRequest.cs
new file mode 100644
index 00000000..47d5a035
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByDetailIdRequest.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id} 接口的请求。
+ ///
+ public class GetTransferBatchDetailByDetailIdRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置微信批次单号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string BatchId { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置微信明细单号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string DetailId { get; set; } = string.Empty;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByDetailIdResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByDetailIdResponse.cs
new file mode 100644
index 00000000..6b113033
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByDetailIdResponse.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id} 接口的响应。
+ ///
+ public class GetTransferBatchDetailByDetailIdResponse : GetTransferBatchDetailByOutDetailNumberResponse
+ {
+ ///
+ /// 获取或设置微信商户号。
+ ///
+ [Newtonsoft.Json.JsonProperty("mchid")]
+ [System.Text.Json.Serialization.JsonPropertyName("mchid")]
+ public string MerchantId { get; set; } = default!;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberRequest.cs
new file mode 100644
index 00000000..83117adb
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberRequest.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no} 接口的请求。
+ ///
+ public class GetTransferBatchDetailByOutDetailNumberRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string OutBatchNumber { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置商户明细单号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string OutDetailNumber { get; set; } = string.Empty;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberResponse.cs
new file mode 100644
index 00000000..12cae7b9
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberResponse.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no} 接口的响应。
+ ///
+ public class GetTransferBatchDetailByOutDetailNumberResponse : WechatTenpayResponse
+ {
+ ///
+ /// 获取或设置微信 AppId。
+ ///
+ [Newtonsoft.Json.JsonProperty("appid")]
+ [System.Text.Json.Serialization.JsonPropertyName("appid")]
+ public string? AppId { get; set; }
+
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string OutBatchNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置微信批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("batch_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("batch_id")]
+ public string BatchId { get; set; } = default!;
+
+ ///
+ /// 获取或设置商户明细单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_detail_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_detail_no")]
+ public string OutDetailNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置微信明细单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("detail_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("detail_id")]
+ public string DetailId { get; set; } = default!;
+
+ ///
+ /// 获取或设置明细状态。
+ ///
+ [Newtonsoft.Json.JsonProperty("detail_status")]
+ [System.Text.Json.Serialization.JsonPropertyName("detail_status")]
+ public string DetailStatus { get; set; } = default!;
+
+ ///
+ /// 获取或设置转账金额(单位:分)。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_amount")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_amount")]
+ public int TransferAmount { get; set; }
+
+ ///
+ /// 获取或设置转账备注。
+ ///
+ [Newtonsoft.Json.JsonProperty("transfer_remark")]
+ [System.Text.Json.Serialization.JsonPropertyName("transfer_remark")]
+ public string TransferRemark { get; set; } = default!;
+
+ ///
+ /// 获取或设置失败原因。
+ ///
+ [Newtonsoft.Json.JsonProperty("fail_reason")]
+ [System.Text.Json.Serialization.JsonPropertyName("fail_reason")]
+ public string? FailReason { get; set; }
+
+ ///
+ /// 获取或设置收款用户 OpenId。
+ ///
+ [Newtonsoft.Json.JsonProperty("openid")]
+ [System.Text.Json.Serialization.JsonPropertyName("openid")]
+ public string OpenId { get; set; } = default!;
+
+ ///
+ /// 获取或设置收款用户姓名(需使用商户私钥解密)。
+ ///
+ [Newtonsoft.Json.JsonProperty("user_name")]
+ [System.Text.Json.Serialization.JsonPropertyName("user_name")]
+ public virtual string UserName { get; set; } = default!;
+
+ ///
+ /// 获取或设置转账发起时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("initiate_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("initiate_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ public DateTimeOffset InitiateTime { get; set; }
+
+ ///
+ /// 获取或设置明细更新时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("update_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("update_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339DateTimeOffsetConverter))]
+ public DateTimeOffset UpdateTime { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/CreateTransferBillReceiptRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/CreateTransferBillReceiptRequest.cs
new file mode 100644
index 00000000..b7fd860f
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/CreateTransferBillReceiptRequest.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [POST] /transfer/bill-receipt 接口的请求。
+ ///
+ public class CreateTransferBillReceiptRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string OutBatchNumber { get; set; } = string.Empty;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/CreateTransferBillReceiptResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/CreateTransferBillReceiptResponse.cs
new file mode 100644
index 00000000..0b9de23e
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/CreateTransferBillReceiptResponse.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [POST] /transfer/bill-receipt 接口的响应。
+ ///
+ public class CreateTransferBillReceiptResponse : GetTransferBillReceiptByOutBatchNumberResponse
+ {
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberRequest.cs
new file mode 100644
index 00000000..444ad849
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberRequest.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer/bill-receipt/{out_batch_no} 接口的请求。
+ ///
+ public class GetTransferBillReceiptByOutBatchNumberRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string OutBatchNumber { get; set; } = string.Empty;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberResponse.cs
new file mode 100644
index 00000000..f11e883b
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberResponse.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer/bill-receipt/{out_batch_no} 接口的响应。
+ ///
+ public class GetTransferBillReceiptByOutBatchNumberResponse : WechatTenpayResponse
+ {
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string OutBatchNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置电子回单申请单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("signature_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("signature_no")]
+ public string SignatureNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置电子回单状态。
+ ///
+ [Newtonsoft.Json.JsonProperty("signature_status")]
+ [System.Text.Json.Serialization.JsonPropertyName("signature_status")]
+ public string? SignatureStatus { get; set; }
+
+ ///
+ /// 获取或设置电子回单文件的哈希方法。
+ ///
+ [Newtonsoft.Json.JsonProperty("hash_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("hash_type")]
+ public string? HashType { get; set; }
+
+ ///
+ /// 获取或设置电子回单文件的哈希值。
+ ///
+ [Newtonsoft.Json.JsonProperty("hash_value")]
+ [System.Text.Json.Serialization.JsonPropertyName("hash_value")]
+ public string? HashValue { get; set; }
+
+ ///
+ /// 获取或设置电子回单文件的下载地址。
+ ///
+ [Newtonsoft.Json.JsonProperty("download_url")]
+ [System.Text.Json.Serialization.JsonPropertyName("download_url")]
+ public string? DownloadUrl { get; set; }
+
+ ///
+ /// 获取或设置创建时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("create_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339NullableDateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("create_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339NullableDateTimeOffsetConverter))]
+ public DateTimeOffset? CreateTime { get; set; }
+
+ ///
+ /// 获取或设置更新时间。
+ ///
+ [Newtonsoft.Json.JsonProperty("update_time")]
+ [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.RFC3339NullableDateTimeOffsetConverter))]
+ [System.Text.Json.Serialization.JsonPropertyName("update_time")]
+ [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.RFC3339NullableDateTimeOffsetConverter))]
+ public DateTimeOffset? UpdateTime { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/CreateTransferDetailElectronicReceiptRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/CreateTransferDetailElectronicReceiptRequest.cs
new file mode 100644
index 00000000..968c919c
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/CreateTransferDetailElectronicReceiptRequest.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [POST] /transfer-detail/electronic-receipts 接口的请求。
+ ///
+ public class CreateTransferDetailElectronicReceiptRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置受理类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("accept_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("accept_type")]
+ public string AcceptType { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string? OutBatchNumber { get; set; }
+
+ ///
+ /// 获取或设置商户明细单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_detail_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_detail_no")]
+ public string OutDetailNumber { get; set; } = string.Empty;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/CreateTransferDetailElectronicReceiptResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/CreateTransferDetailElectronicReceiptResponse.cs
new file mode 100644
index 00000000..459d1e9c
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/CreateTransferDetailElectronicReceiptResponse.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [POST] /transfer-detail/electronic-receipts 接口的响应。
+ ///
+ public class CreateTransferDetailElectronicReceiptResponse : GetTransferDetailElectronicReceiptByOutDetailNumberResponse
+ {
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberRequest.cs
new file mode 100644
index 00000000..26f954e4
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberRequest.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer-detail/electronic-receipts 接口的请求。
+ ///
+ public class GetTransferDetailElectronicReceiptByOutDetailNumberRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置受理类型。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string AcceptType { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string? OutBatchNumber { get; set; }
+
+ ///
+ /// 获取或设置商户明细单号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string OutDetailNumber { get; set; } = string.Empty;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberResponse.cs
new file mode 100644
index 00000000..bcaf988a
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberResponse.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /transfer-detail/electronic-receipts 接口的响应。
+ ///
+ public class GetTransferDetailElectronicReceiptByOutDetailNumberResponse : WechatTenpayResponse
+ {
+ ///
+ /// 获取或设置受理类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("accept_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("accept_type")]
+ public string AcceptType { get; set; } = default!;
+
+ ///
+ /// 获取或设置商户批次单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_batch_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
+ public string OutBatchNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置商户明细单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("out_detail_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("out_detail_no")]
+ public string OutDetailNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置电子回单申请单号。
+ ///
+ [Newtonsoft.Json.JsonProperty("signature_no")]
+ [System.Text.Json.Serialization.JsonPropertyName("signature_no")]
+ public string SignatureNumber { get; set; } = default!;
+
+ ///
+ /// 获取或设置电子回单状态。
+ ///
+ [Newtonsoft.Json.JsonProperty("signature_status")]
+ [System.Text.Json.Serialization.JsonPropertyName("signature_status")]
+ public string? SignatureStatus { get; set; }
+
+ ///
+ /// 获取或设置电子回单文件的哈希方法。
+ ///
+ [Newtonsoft.Json.JsonProperty("hash_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("hash_type")]
+ public string? HashType { get; set; }
+
+ ///
+ /// 获取或设置电子回单文件的哈希值。
+ ///
+ [Newtonsoft.Json.JsonProperty("hash_value")]
+ [System.Text.Json.Serialization.JsonPropertyName("hash_value")]
+ public string? HashValue { get; set; }
+
+ ///
+ /// 获取或设置电子回单文件的下载地址。
+ ///
+ [Newtonsoft.Json.JsonProperty("download_url")]
+ [System.Text.Json.Serialization.JsonPropertyName("download_url")]
+ public string? DownloadUrl { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/SKIT.FlurlHttpClient.Wechat.TenpayV3.csproj b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/SKIT.FlurlHttpClient.Wechat.TenpayV3.csproj
index 6bd92f8f..482f7c76 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/SKIT.FlurlHttpClient.Wechat.TenpayV3.csproj
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/SKIT.FlurlHttpClient.Wechat.TenpayV3.csproj
@@ -12,7 +12,7 @@
MIT
https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat
Flurl.Http Wechat Weixin MicroMessage Tenpay WechatPay WeixinPay Wxpay 微信 微信支付 微信商户
- 1.2.1
+ 1.3.0
Flurl.Http client for Wechat Tenpay API. 基于 Flurl.Http 的微信支付 API v3 版客户端,支持直连商户、服务商模式,支持基础支付、代金券、商家券、委托营销、消费卡、支付有礼、微信支付分、微信先享卡、支付即服务、点金计划、智慧商圈、电商收付通、消费者投诉等功能。
Fu Diwei
git
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Settings/ICertificateStorer.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Settings/ICertificateStorer.cs
new file mode 100644
index 00000000..0c99f9ff
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Settings/ICertificateStorer.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings
+{
+ ///
+ /// 微信商户平台证书存储器接口。
+ ///
+ public interface ICertificateStorer
+ {
+ ///
+ /// 根据证书序列号获取证书(cer 格式)。
+ ///
+ ///
+ ///
+ string? Get(string serialNumber);
+
+ ///
+ /// 设置证书序列号与证书(cer 格式)的映射关系。
+ ///
+ ///
+ ///
+ void Set(string serialNumber, string certificate);
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Settings/InMemoryCertificateStorer.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Settings/InMemoryCertificateStorer.cs
new file mode 100644
index 00000000..37afe581
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Settings/InMemoryCertificateStorer.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings
+{
+ ///
+ /// 一个基于内存实现的 。
+ ///
+ public class InMemoryCertificateStorer : ICertificateStorer
+ {
+ public IDictionary _dict;
+
+ public InMemoryCertificateStorer()
+ {
+ _dict = new ConcurrentDictionary();
+ }
+
+ string? ICertificateStorer.Get(string serialNumber)
+ {
+ if (serialNumber == null) throw new ArgumentNullException(nameof(serialNumber));
+
+ return _dict[serialNumber];
+ }
+
+ void ICertificateStorer.Set(string serialNumber, string certificate)
+ {
+ if (serialNumber == null) throw new ArgumentNullException(nameof(serialNumber));
+ if (certificate == null) throw new ArgumentNullException(nameof(certificate));
+
+ _dict[serialNumber] = certificate;
+ }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayAuthSchemes.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayAuthSchemes.cs
deleted file mode 100644
index 372fecdd..00000000
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayAuthSchemes.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-
-namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
-{
- ///
- /// 微信支付 API 接口签名认证方式。
- ///
- public static class WechatTenpayAuthSchemes
- {
- ///
- /// WECHATPAY2-SHA256-RSA2048(默认)。
- ///
- public const string WECHATPAY2_SHA256_RSA2048 = "WECHATPAY2-SHA256-RSA2048";
- }
-}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClient.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClient.cs
index a7afc7a2..d2e084fb 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClient.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClient.cs
@@ -39,6 +39,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
internal string WechatMerchantV3Secret { get; }
+ ///
+ /// 获取当前客户端使用的微信商户平台证书存储器。
+ ///
+ internal Settings.ICertificateStorer? WechatCertificateStorer { get; }
+
///
/// 获取当前客户端使用的 JSON 序列化器。
///
@@ -59,6 +64,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
WechatMerchantCertSerialNumber = options.MerchantCertSerialNumber;
WechatMerchantCertPrivateKey = options.MerchantCertPrivateKey;
WechatMerchantV3Secret = options.MerchantV3Secret;
+ WechatCertificateStorer = options.CertificateStorer;
FlurlClient.BaseUrl = options.Endpoints ?? WechatTenpayEndpoints.DEFAULT;
FlurlClient.Headers.Remove("Accept");
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClientOptions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClientOptions.cs
index a73a442d..3c339680 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClientOptions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClientOptions.cs
@@ -34,9 +34,9 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
/// 获取或设置微信支付 API 签名认证方式。
- /// 默认值:
+ /// 默认值:
///
- public string AuthScheme { get; set; } = WechatTenpayAuthSchemes.WECHATPAY2_SHA256_RSA2048;
+ public string AuthScheme { get; set; } = Constants.SignAlgorithms.WECHATPAY2_SHA256_RSA2048;
///
/// 获取或设置微信商户号。
@@ -57,5 +57,11 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
/// 获取或设置微信商户 API 证书私钥。
///
public string MerchantCertPrivateKey { get; set; } = default!;
+
+ ///
+ /// 获取或设置微信商户平台证书存储器。
+ /// 默认值:
+ ///
+ public Settings.ICertificateStorer? CertificateStorer { get; set; } = new Settings.InMemoryCertificateStorer();
}
}
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsResponse.json
new file mode 100644
index 00000000..6ebcaaa4
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundMerchantIncomeRecordsResponse.json
@@ -0,0 +1,18 @@
+{
+ "total_count": 100,
+ "offset": 0,
+ "limit": 100,
+ "data": [
+ {
+ "mchid": "2480253391",
+ "account_type": "BASIC",
+ "income_record_type": "OFFLINERECHARGE",
+ "income_record_id": "4200000811202011056138519459",
+ "amount": 100,
+ "success_time": "2017-12-08T00:08:00.00+08:00",
+ "bank_name": "招商银行",
+ "bank_account_name": "财付通支付科技有限公司",
+ "bank_account_number": "****6473"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsResponse.json
new file mode 100644
index 00000000..28f6a57f
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/MerchantFundIncomeRecords/QueryMerchantFundPartnerIncomeRecordsResponse.json
@@ -0,0 +1,18 @@
+{
+ "total_count": 0,
+ "offset": 0,
+ "limit": 0,
+ "data": [
+ {
+ "sub_mchid": "2480253391",
+ "account_type": "BASIC",
+ "income_record_type": "OFFLINERECHARGE",
+ "income_record_id": "4200000811202011056138519459",
+ "amount": 2734921,
+ "success_time": "2017-12-08T00:08:00.00+08:00",
+ "bank_name": "招商银行",
+ "bank_account_name": "北京三快科技有限公司",
+ "bank_account_number": "****6473"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/CreatePartnerTransferBatchRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/CreatePartnerTransferBatchRequest.json
new file mode 100644
index 00000000..d7d3629e
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/CreatePartnerTransferBatchRequest.json
@@ -0,0 +1,22 @@
+{
+ "sub_mchid": "1900000109",
+ "sub_appid": "wxf636efh567hg4356",
+ "authorization_type": "INFORMATION_AUTHORIZATION_TYPE",
+ "out_batch_no": "plfk2020042013",
+ "batch_name": "2019年1月深圳分部报销单",
+ "batch_remark": "2019年1月深圳分部报销单",
+ "total_amount": 4000000,
+ "total_num": 200,
+ "transfer_detail_list": [
+ {
+ "out_detail_no": "x23zy545Bd5436",
+ "transfer_amount": 200000,
+ "transfer_remark": "2020年4月报销",
+ "openid": "o-MYE42l80oelYMDE34nYD456Xoy",
+ "user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
+ "user_id_card": "8609cb22e1774a50a930e414cc71eca06121bcd266335cda230d24a7886a8d9f"
+ }
+ ],
+ "sp_appid": "wxf636efh567hg4388",
+ "transfer_purpose": "COMMISSION"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/CreatePartnerTransferBatchResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/CreatePartnerTransferBatchResponse.json
new file mode 100644
index 00000000..57ba85e0
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/CreatePartnerTransferBatchResponse.json
@@ -0,0 +1,5 @@
+{
+ "out_batch_no": "plfk2020042013",
+ "batch_id": "1030000071100999991182020050700019480001",
+ "create_time": "2015-05-20T13:29:35.120+08:00"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdResponse.json
new file mode 100644
index 00000000..195bae4c
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByBatchIdResponse.json
@@ -0,0 +1,29 @@
+{
+ "sp_mchid": "1900001109",
+ "sub_mchid": "1900000109",
+ "out_batch_no": "plfk2020042013",
+ "batch_id": "1030000071100999991182020050700019480001",
+ "sub_appid": "wxf636efh567hg4356",
+ "batch_status": "ACCEPTED",
+ "batch_type": "API",
+ "authorization_type": "INFORMATION_AUTHORIZATION_TYPE",
+ "batch_name": "2019年1月深圳分部报销单",
+ "batch_remark": "2019年1月深圳分部报销单",
+ "close_reason": "OVERDUE_CLOSE",
+ "total_amount": 4000000,
+ "total_num": 200,
+ "create_time": "2015-05-20T13:29:35.120+08:00",
+ "update_time": "2015-05-20T13:29:35.120+08:00",
+ "success_amount": 3900000,
+ "success_num": 199,
+ "fail_amount": 100000,
+ "fail_num": 1,
+ "transfer_detail_list": [
+ {
+ "detail_id": "1040000071100999991182020050700019500100",
+ "out_detail_no": "x23zy545Bd5436",
+ "detail_status": "SUCCESS"
+ }
+ ],
+ "transfer_purpose": "COMMISSION"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberResponse.json
new file mode 100644
index 00000000..195bae4c
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchByOutBatchNumberResponse.json
@@ -0,0 +1,29 @@
+{
+ "sp_mchid": "1900001109",
+ "sub_mchid": "1900000109",
+ "out_batch_no": "plfk2020042013",
+ "batch_id": "1030000071100999991182020050700019480001",
+ "sub_appid": "wxf636efh567hg4356",
+ "batch_status": "ACCEPTED",
+ "batch_type": "API",
+ "authorization_type": "INFORMATION_AUTHORIZATION_TYPE",
+ "batch_name": "2019年1月深圳分部报销单",
+ "batch_remark": "2019年1月深圳分部报销单",
+ "close_reason": "OVERDUE_CLOSE",
+ "total_amount": 4000000,
+ "total_num": 200,
+ "create_time": "2015-05-20T13:29:35.120+08:00",
+ "update_time": "2015-05-20T13:29:35.120+08:00",
+ "success_amount": 3900000,
+ "success_num": 199,
+ "fail_amount": 100000,
+ "fail_num": 1,
+ "transfer_detail_list": [
+ {
+ "detail_id": "1040000071100999991182020050700019500100",
+ "out_detail_no": "x23zy545Bd5436",
+ "detail_status": "SUCCESS"
+ }
+ ],
+ "transfer_purpose": "COMMISSION"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdResponse.json
new file mode 100644
index 00000000..9a221567
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByDetailIdResponse.json
@@ -0,0 +1,16 @@
+{
+ "sp_mchid": "1900001109",
+ "out_batch_no": "plfk2020042013",
+ "batch_id": "1030000071100999991182020050700019480001",
+ "appid": "wxf636efh567hg4356",
+ "out_detail_no": "x23zy545Bd5436",
+ "detail_id": "1040000071100999991182020050700019500100",
+ "detail_status": "SUCCESS",
+ "transfer_amount": 200000,
+ "transfer_remark": "2020年4月报销",
+ "fail_reason": "ACCOUNT_FROZEN",
+ "openid": "o-MYE42l80oelYMDE34nYD456Xoy",
+ "username": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
+ "initiate_time": "2015-05-20T13:29:35.120+08:00",
+ "update_time": "2015-05-20T13:29:35.120+08:00"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberResponse.json
new file mode 100644
index 00000000..9a221567
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/PartnerTransfer/Batches/GetPartnerTransferBatchDetailByOutDetailNumberResponse.json
@@ -0,0 +1,16 @@
+{
+ "sp_mchid": "1900001109",
+ "out_batch_no": "plfk2020042013",
+ "batch_id": "1030000071100999991182020050700019480001",
+ "appid": "wxf636efh567hg4356",
+ "out_detail_no": "x23zy545Bd5436",
+ "detail_id": "1040000071100999991182020050700019500100",
+ "detail_status": "SUCCESS",
+ "transfer_amount": 200000,
+ "transfer_remark": "2020年4月报销",
+ "fail_reason": "ACCOUNT_FROZEN",
+ "openid": "o-MYE42l80oelYMDE34nYD456Xoy",
+ "username": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
+ "initiate_time": "2015-05-20T13:29:35.120+08:00",
+ "update_time": "2015-05-20T13:29:35.120+08:00"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/CreateTransferBatchRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/CreateTransferBatchRequest.json
new file mode 100644
index 00000000..763bb22e
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/CreateTransferBatchRequest.json
@@ -0,0 +1,18 @@
+{
+ "appid": "wxf636efh567hg4356",
+ "out_batch_no": "plfk2020042013",
+ "batch_name": "2019年1月深圳分部报销单",
+ "batch_remark": "2019年1月深圳分部报销单",
+ "total_amount": 4000000,
+ "total_num": 200,
+ "transfer_detail_list": [
+ {
+ "out_detail_no": "x23zy545Bd5436",
+ "transfer_amount": 200000,
+ "transfer_remark": "2020年4月报销",
+ "openid": "o-MYE42l80oelYMDE34nYD456Xoy",
+ "user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
+ "user_id_card": "8609cb22e1774a50a930e414cc71eca06121bcd266335cda230d24a7886a8d9f"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/CreateTransferBatchResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/CreateTransferBatchResponse.json
new file mode 100644
index 00000000..57ba85e0
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/CreateTransferBatchResponse.json
@@ -0,0 +1,5 @@
+{
+ "out_batch_no": "plfk2020042013",
+ "batch_id": "1030000071100999991182020050700019480001",
+ "create_time": "2015-05-20T13:29:35.120+08:00"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByBatchIdRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByBatchIdRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByBatchIdRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByBatchIdResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByBatchIdResponse.json
new file mode 100644
index 00000000..47d00ef7
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByBatchIdResponse.json
@@ -0,0 +1,28 @@
+{
+ "transfer_batch": {
+ "mchid": "1900001109",
+ "out_batch_no": "plfk2020042013",
+ "batch_id": "1030000071100999991182020050700019480001",
+ "appid": "wxf636efh567hg4356",
+ "batch_status": "ACCEPTED",
+ "batch_type": "API",
+ "batch_name": "2019年1月深圳分部报销单",
+ "batch_remark": "2019年1月深圳分部报销单",
+ "close_reason": "OVERDUE_CLOSE",
+ "total_amount": 4000000,
+ "total_num": 200,
+ "create_time": "2015-05-20T13:29:35.120+08:00",
+ "update_time": "2015-05-20T13:29:35.120+08:00",
+ "success_amount": 3900000,
+ "success_num": 199,
+ "fail_amount": 100000,
+ "fail_num": 1
+ },
+ "transfer_detail_list": [
+ {
+ "detail_id": "1040000071100999991182020050700019500100",
+ "out_detail_no": "x23zy545Bd5436",
+ "detail_status": "SUCCESS"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByOutBatchNumberRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByOutBatchNumberRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByOutBatchNumberRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByOutBatchNumberResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByOutBatchNumberResponse.json
new file mode 100644
index 00000000..47d00ef7
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchByOutBatchNumberResponse.json
@@ -0,0 +1,28 @@
+{
+ "transfer_batch": {
+ "mchid": "1900001109",
+ "out_batch_no": "plfk2020042013",
+ "batch_id": "1030000071100999991182020050700019480001",
+ "appid": "wxf636efh567hg4356",
+ "batch_status": "ACCEPTED",
+ "batch_type": "API",
+ "batch_name": "2019年1月深圳分部报销单",
+ "batch_remark": "2019年1月深圳分部报销单",
+ "close_reason": "OVERDUE_CLOSE",
+ "total_amount": 4000000,
+ "total_num": 200,
+ "create_time": "2015-05-20T13:29:35.120+08:00",
+ "update_time": "2015-05-20T13:29:35.120+08:00",
+ "success_amount": 3900000,
+ "success_num": 199,
+ "fail_amount": 100000,
+ "fail_num": 1
+ },
+ "transfer_detail_list": [
+ {
+ "detail_id": "1040000071100999991182020050700019500100",
+ "out_detail_no": "x23zy545Bd5436",
+ "detail_status": "SUCCESS"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByDetailIdRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByDetailIdRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByDetailIdRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByDetailIdResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByDetailIdResponse.json
new file mode 100644
index 00000000..03610c54
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByDetailIdResponse.json
@@ -0,0 +1,16 @@
+{
+ "mchid": "1900001109",
+ "out_batch_no": "plfk2020042013",
+ "batch_id": "1030000071100999991182020050700019480001",
+ "appid": "wxf636efh567hg4356",
+ "out_detail_no": "x23zy545Bd5436",
+ "detail_id": "1040000071100999991182020050700019500100",
+ "detail_status": "SUCCESS",
+ "transfer_amount": 200000,
+ "transfer_remark": "2020年4月报销",
+ "fail_reason": "ACCOUNT_FROZEN",
+ "openid": "o-MYE42l80oelYMDE34nYD456Xoy",
+ "user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
+ "initiate_time": "2015-05-20T13:29:35.120+08:00",
+ "update_time": "2015-05-20T13:29:35.120+08:00"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberResponse.json
new file mode 100644
index 00000000..f98a9da7
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Batches/GetTransferBatchDetailByOutDetailNumberResponse.json
@@ -0,0 +1,15 @@
+{
+ "out_batch_no": "plfk2020042013",
+ "batch_id": "1030000071100999991182020050700019480001",
+ "appid": "wxf636efh567hg4356",
+ "out_detail_no": "x23zy545Bd5436",
+ "detail_id": "1040000071100999991182020050700019500100",
+ "detail_status": "SUCCESS",
+ "transfer_amount": 200000,
+ "transfer_remark": "2020年4月报销",
+ "fail_reason": "ACCOUNT_FROZEN",
+ "openid": "o-MYE42l80oelYMDE34nYD456Xoy",
+ "user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
+ "initiate_time": "2015-05-20T13:29:35.120+08:00",
+ "update_time": "2015-05-20T13:29:35.120+08:00"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/CreateTransferBillReceiptRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/CreateTransferBillReceiptRequest.json
new file mode 100644
index 00000000..aec1ac18
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/CreateTransferBillReceiptRequest.json
@@ -0,0 +1,3 @@
+{
+ "out_batch_no": "plfk2020042013"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/CreateTransferBillReceiptResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/CreateTransferBillReceiptResponse.json
new file mode 100644
index 00000000..8ead5382
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/CreateTransferBillReceiptResponse.json
@@ -0,0 +1,10 @@
+{
+ "out_batch_no": "plfk2020042013",
+ "signature_no": "1050000010509999485212020110200058820001",
+ "signature_status": "ACCEPTED",
+ "hash_type": "SHA256",
+ "hash_value": "DE731F35146A0BEFADE5DB9D1E468D96C01CA8898119C674FEE9F11F4DBE5529",
+ "download_url": "https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx",
+ "create_time": "2020-05-20T13:29:35.120+08:00",
+ "update_time": "2020-05-21T13:29:35.120+08:00"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberResponse.json
new file mode 100644
index 00000000..8ead5382
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/BillReceipt/GetTransferBillReceiptByOutBatchNumberResponse.json
@@ -0,0 +1,10 @@
+{
+ "out_batch_no": "plfk2020042013",
+ "signature_no": "1050000010509999485212020110200058820001",
+ "signature_status": "ACCEPTED",
+ "hash_type": "SHA256",
+ "hash_value": "DE731F35146A0BEFADE5DB9D1E468D96C01CA8898119C674FEE9F11F4DBE5529",
+ "download_url": "https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx",
+ "create_time": "2020-05-20T13:29:35.120+08:00",
+ "update_time": "2020-05-21T13:29:35.120+08:00"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/CreateTransferDetailElectronicReceiptRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/CreateTransferDetailElectronicReceiptRequest.json
new file mode 100644
index 00000000..950ad60a
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/CreateTransferDetailElectronicReceiptRequest.json
@@ -0,0 +1,5 @@
+{
+ "accept_type": "BATCH_TRANSFER",
+ "out_batch_no": "GD2021011610162610BBdkkIwcu3",
+ "out_detail_no": "mx0911231610162610v4CNkO4HAf"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/CreateTransferDetailElectronicReceiptResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/CreateTransferDetailElectronicReceiptResponse.json
new file mode 100644
index 00000000..bb8ce743
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/CreateTransferDetailElectronicReceiptResponse.json
@@ -0,0 +1,10 @@
+{
+ "accept_type": "BATCH_TRANSFER",
+ "out_batch_no": "GD2021011610162610BBdkkIwcu3",
+ "out_detail_no": "mx0911231610162610v4CNkO4HAf",
+ "signature_no": "1050000010509999485212020110200058820001",
+ "signature_status": "ACCEPTED",
+ "hash_type": "SHA256",
+ "hash_value": "DE731F35146A0BEFADE5DB9D1E468D96C01CA8898119C674FEE9F11F4DBE5529",
+ "download_url": "https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberRequest.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberRequest.json
new file mode 100644
index 00000000..22fdca1b
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberRequest.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberResponse.json
new file mode 100644
index 00000000..bb8ce743
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/Transfer/Detail/GetTransferDetailElectronicReceiptByOutDetailNumberResponse.json
@@ -0,0 +1,10 @@
+{
+ "accept_type": "BATCH_TRANSFER",
+ "out_batch_no": "GD2021011610162610BBdkkIwcu3",
+ "out_detail_no": "mx0911231610162610v4CNkO4HAf",
+ "signature_no": "1050000010509999485212020110200058820001",
+ "signature_status": "ACCEPTED",
+ "hash_type": "SHA256",
+ "hash_value": "DE731F35146A0BEFADE5DB9D1E468D96C01CA8898119C674FEE9F11F4DBE5529",
+ "download_url": "https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx"
+}
\ No newline at end of file
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/WechatTenpayResponseVerificationTests.cs b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/WechatTenpayResponseVerificationTests.cs
index b331786d..12b3e907 100644
--- a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/WechatTenpayResponseVerificationTests.cs
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/WechatTenpayResponseVerificationTests.cs
@@ -21,7 +21,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
Assert.NotNull(response.WechatpayCertSerialNumber);
Assert.NotNull(response.WechatpaySignature);
- TestClients.Instance.DecryptResponseEncryptedData(response);
+ TestClients.Instance.DecryptResponseEncryptedData(ref response);
var certificateModel = response.CertificateList.SingleOrDefault(e => e.SerialNumber == response.WechatpayCertSerialNumber);
Assert.NotNull(certificateModel);