feat(tenpayv3): 新增品牌红包相关接口

This commit is contained in:
Fu Diwei 2025-07-13 20:37:38 +08:00
parent 3d52f354a1
commit f3f3800547
27 changed files with 970 additions and 5 deletions

View File

@ -58,6 +58,7 @@
| √ | 运营工具:电子发票 | 直连商户 & 合作伙伴 | |
| √ | 运营工具:点金计划 | 合作伙伴 | |
| × | <del>运营工具:现金红包</del> | 直连商户 & 合作伙伴 | 官方未提供 v3 API |
| √ | 运营工具:品牌红包 | 直连商户 | |
| √ | 扩展工具:分账 | 直连商户 & 合作伙伴 | |
| √ | 扩展工具:连锁品牌分账 | 合作伙伴 | |
| √ | 扩展工具:消费者投诉 2.0 | 直连商户 & 合作伙伴 | |
@ -209,7 +210,6 @@
- 微信单号查询电子回单:`GetFundAppMerchantTransferElecsignByTransferBillNumber`
- 商家转账到 QQ 钱包
- 发起转账到 QQ 钱包:`CreateFundAppMerchantTransferToQQWalletBill`
@ -488,6 +488,18 @@
- 将电子发票插入微信用户卡包:`CreateNewTaxControlFapiaoApplicationCard`
- 品牌红包
- 品牌商户发放红包:`CreateFundAppBrandRedPacketBrandMerchantBatch`
- 商家批次单号查询批次单:`GetFundAppBrandRedPacketBrandMerchantBatchByOutBatchNumber`
- 商家明细单号查询明细单:`GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumber`
- 微信支付批次单号查询批次单:`GetFundAppBrandRedPacketBrandMerchantBatchByBatchNumber`
- 微信支付明细单号查询明细单:`GetFundAppBrandRedPacketBrandMerchantBatchDetailByDetailNumber`
- 商家充值
- 申请银行转账充值:`ApplyBankTransferRecharge`

View File

@ -258,5 +258,121 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
}
#endregion
#endregion
#region BrandRedPacket
/// <summary>
/// <para>异步调用 [POST] /fund-app/brand-redpacket/brand-merchant-batches 接口。</para>
/// <para>
/// REF: <br/>
/// <![CDATA[ https://pay.weixin.qq.com/doc/v3/merchant/4014310358 ]]>
/// </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.CreateFundAppBrandRedPacketBrandMerchantBatchResponse> ExecuteCreateFundAppBrandRedPacketBrandMerchantBatchAsync(this WechatTenpayClient client, Models.CreateFundAppBrandRedPacketBrandMerchantBatchRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateFlurlRequest(request, HttpMethod.Post, "fund-app", "brand-redpacket", "brand-merchant-batches");
return await client.SendFlurlRequestAsJsonAsync<Models.CreateFundAppBrandRedPacketBrandMerchantBatchResponse>(flurlReq, data: request, cancellationToken: cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// <para>异步调用 [GET] /fund-app/brand-redpacket/brand-merchant-out-batches/{out_batch_no} 接口。</para>
/// <para>
/// REF: <br/>
/// <![CDATA[ https://pay.weixin.qq.com/doc/v3/merchant/4014310378 ]]>
/// </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.GetFundAppBrandRedPacketBrandMerchantBatchByOutBatchNumberResponse> ExecuteGetFundAppBrandRedPacketBrandMerchantBatchByOutBatchNumberAsync(this WechatTenpayClient client, Models.GetFundAppBrandRedPacketBrandMerchantBatchByOutBatchNumberRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateFlurlRequest(request, HttpMethod.Get, "fund-app", "brand-redpacket", "brand-merchant-out-batches", request.OutBatchNumber)
.SetQueryParam("need_query_detail", request.RequireQueryDetail)
.SetQueryParam("detail_state", request.DetailState);
return await client.SendFlurlRequestAsJsonAsync<Models.GetFundAppBrandRedPacketBrandMerchantBatchByOutBatchNumberResponse>(flurlReq, data: request, cancellationToken: cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// <para>异步调用 [GET] /fund-app/brand-redpacket/brand-merchant-batches/{batch_no} 接口。</para>
/// <para>
/// REF: <br/>
/// <![CDATA[ https://pay.weixin.qq.com/doc/v3/merchant/4014310369 ]]>
/// </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.GetFundAppBrandRedPacketBrandMerchantBatchByBatchNumberResponse> ExecuteGetFundAppBrandRedPacketBrandMerchantBatchByBatchNumberAsync(this WechatTenpayClient client, Models.GetFundAppBrandRedPacketBrandMerchantBatchByBatchNumberRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateFlurlRequest(request, HttpMethod.Get, "fund-app", "brand-redpacket", "brand-merchant-batches", request.BatchNumber)
.SetQueryParam("need_query_detail", request.RequireQueryDetail)
.SetQueryParam("detail_state", request.DetailState);
return await client.SendFlurlRequestAsJsonAsync<Models.GetFundAppBrandRedPacketBrandMerchantBatchByBatchNumberResponse>(flurlReq, data: request, cancellationToken: cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// <para>异步调用 [GET] /fund-app/brand-redpacket/brand-merchant-out-batches/{out_batch_no}/out-details/{out_detail_no} 接口。</para>
/// <para>
/// REF: <br/>
/// <![CDATA[ https://pay.weixin.qq.com/doc/v3/merchant/4014310391 ]]>
/// </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberResponse> ExecuteGetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberAsync(this WechatTenpayClient client, Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateFlurlRequest(request, HttpMethod.Get, "fund-app", "brand-redpacket", "brand-merchant-out-batches", request.OutBatchNumber, "out-details", request.OutDetailNumber);
return await client.SendFlurlRequestAsJsonAsync<Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberResponse>(flurlReq, data: request, cancellationToken: cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// <para>异步调用 [GET] /fund-app/brand-redpacket/brand-merchant-batches/{batch_no}/details/{detail_no} 接口。</para>
/// <para>
/// REF: <br/>
/// <![CDATA[ https://pay.weixin.qq.com/doc/v3/merchant/4014310384 ]]>
/// </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByDetailNumberResponse> ExecuteGetFundAppBrandRedPacketBrandMerchantBatchDetailByDetailNumberAsync(this WechatTenpayClient client, Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByDetailNumberRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateFlurlRequest(request, HttpMethod.Get, "fund-app", "brand-redpacket", "brand-merchant-batches", request.BatchNumber, "out-details", request.DetailNumber);
return await client.SendFlurlRequestAsJsonAsync<Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByDetailNumberResponse>(flurlReq, data: request, cancellationToken: cancellationToken).ConfigureAwait(false);
}
#endregion
}
}

View File

@ -0,0 +1,124 @@
using System.Collections.Generic;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [POST] /fund-app/brand-redpacket/brand-merchant-batches 接口的请求。</para>
/// </summary>
[WechatTenpaySensitive]
public class CreateFundAppBrandRedPacketBrandMerchantBatchRequest : WechatTenpayRequest
{
public static class Types
{
public class TransferDetail
{
/// <summary>
/// 获取或设置商家明细单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("out_detail_no")]
[System.Text.Json.Serialization.JsonPropertyName("out_detail_no")]
public string OutDetailNumber { get; set; } = string.Empty;
/// <summary>
/// 获取或设置红包金额(单位:分)。
/// </summary>
[Newtonsoft.Json.JsonProperty("amount")]
[System.Text.Json.Serialization.JsonPropertyName("amount")]
public int Amount { get; set; }
/// <summary>
/// 获取或设置接收红包 OpenId。
/// </summary>
[Newtonsoft.Json.JsonProperty("openid")]
[System.Text.Json.Serialization.JsonPropertyName("openid")]
public string OpenId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置接收红包用户姓名(需使用平台公钥/证书加密)。
/// </summary>
[Newtonsoft.Json.JsonProperty("user_name")]
[System.Text.Json.Serialization.JsonPropertyName("user_name")]
[WechatTenpaySensitiveProperty(scheme: Constants.SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256, algorithm: Constants.EncryptionAlgorithms.RSA_2048_ECB_PKCS8_OAEP_WITH_SHA1_AND_MGF1)]
[WechatTenpaySensitiveProperty(scheme: Constants.SignSchemes.WECHATPAY2_SM2_WITH_SM3, algorithm: Constants.EncryptionAlgorithms.SM2_C1C3C2_ASN1)]
public string? UserName { get; set; }
/// <summary>
/// 获取或设置红包备注。
/// </summary>
[Newtonsoft.Json.JsonProperty("remark")]
[System.Text.Json.Serialization.JsonPropertyName("remark")]
public string? Remark { get; set; }
}
}
/// <summary>
/// 获取或设置品牌 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("brand_id")]
[System.Text.Json.Serialization.JsonPropertyName("brand_id")]
public int BrandId { get; set; }
/// <summary>
/// 获取或设置品牌微信 AppId。
/// </summary>
[Newtonsoft.Json.JsonProperty("brand_appid")]
[System.Text.Json.Serialization.JsonPropertyName("brand_appid")]
public string BrandAppId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置品牌红包模板 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("template_id")]
[System.Text.Json.Serialization.JsonPropertyName("template_id")]
public string TemplateId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置商家批次单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("out_batch_no")]
[System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
public string OutBatchNumber { get; set; } = string.Empty;
/// <summary>
/// 获取或设置批次名称。
/// </summary>
[Newtonsoft.Json.JsonProperty("batch_name")]
[System.Text.Json.Serialization.JsonPropertyName("batch_name")]
public string BatchName { get; set; } = string.Empty;
/// <summary>
/// 获取或设置红包总金额(单位:分)。
/// </summary>
[Newtonsoft.Json.JsonProperty("total_amount")]
[System.Text.Json.Serialization.JsonPropertyName("total_amount")]
public int TotalAmount { get; set; }
/// <summary>
/// 获取或设置红包总笔数。
/// </summary>
[Newtonsoft.Json.JsonProperty("total_num")]
[System.Text.Json.Serialization.JsonPropertyName("total_num")]
public int TotalNumber { get; set; }
/// <summary>
/// 获取或设置批次备注。
/// </summary>
[Newtonsoft.Json.JsonProperty("batch_remark")]
[System.Text.Json.Serialization.JsonPropertyName("batch_remark")]
public string BatchRemark { get; set; } = string.Empty;
/// <summary>
/// 获取或设置品牌红包发放场景。
/// </summary>
[Newtonsoft.Json.JsonProperty("scene")]
[System.Text.Json.Serialization.JsonPropertyName("scene")]
public string Scene { get; set; } = string.Empty;
/// <summary>
/// 获取或设置品牌红包明细列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("detail_list")]
[System.Text.Json.Serialization.JsonPropertyName("detail_list")]
public IList<Types.TransferDetail>? TransferDetailList { get; set; }
}
}

View File

@ -0,0 +1,40 @@
using System;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [POST] /fund-app/brand-redpacket/brand-merchant-batches 接口的响应。</para>
/// </summary>
public class CreateFundAppBrandRedPacketBrandMerchantBatchResponse : WechatTenpayResponse
{
/// <summary>
/// 获取或设置商家批次单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("out_batch_no")]
[System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
public string OutBatchNumber { get; set; } = default!;
/// <summary>
/// 获取或设置微信批次单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("batch_no")]
[System.Text.Json.Serialization.JsonPropertyName("batch_no")]
public string BatchNumber { get; set; } = default!;
/// <summary>
/// 获取或设置批次状态。
/// </summary>
[Newtonsoft.Json.JsonProperty("batch_state")]
[System.Text.Json.Serialization.JsonPropertyName("batch_state")]
public string BatchState { get; set; } = default!;
/// <summary>
/// 获取或设置批次创建时间。
/// </summary>
[Newtonsoft.Json.JsonProperty("create_time")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.Rfc3339DateTimeOffsetConverter))]
[System.Text.Json.Serialization.JsonPropertyName("create_time")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.Rfc3339DateTimeOffsetConverter))]
public DateTimeOffset CreateTime { get; set; }
}
}

View File

@ -0,0 +1,29 @@
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [GET] /fund-app/brand-redpacket/brand-merchant-batches/{batch_no} 接口的请求。</para>
/// </summary>
public class GetFundAppBrandRedPacketBrandMerchantBatchByBatchNumberRequest : WechatTenpayRequest
{
/// <summary>
/// 获取或设置微信批次单号。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string BatchNumber { get; set; } = string.Empty;
/// <summary>
/// 获取或设置是否查询红包明细单。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public bool RequireQueryDetail { get; set; }
/// <summary>
/// 获取或设置明细状态。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string? DetailState { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [GET] /fund-app/brand-redpacket/brand-merchant-batches/{batch_no} 接口的响应。</para>
/// </summary>
public class GetFundAppBrandRedPacketBrandMerchantBatchByBatchNumberResponse : GetFundAppBrandRedPacketBrandMerchantBatchByOutBatchNumberResponse
{
}
}

View File

@ -0,0 +1,29 @@
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [GET] /fund-app/brand-redpacket/brand-merchant-out-batches/{out_batch_no} 接口的请求。</para>
/// </summary>
public class GetFundAppBrandRedPacketBrandMerchantBatchByOutBatchNumberRequest : WechatTenpayRequest
{
/// <summary>
/// 获取或设置商家批次单号。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string OutBatchNumber { get; set; } = string.Empty;
/// <summary>
/// 获取或设置是否查询红包明细单。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public bool RequireQueryDetail { get; set; }
/// <summary>
/// 获取或设置明细状态。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string? DetailState { get; set; }
}
}

View File

@ -0,0 +1,174 @@
using System;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [GET] /fund-app/brand-redpacket/brand-merchant-out-batches/{out_batch_no} 接口的响应。</para>
/// </summary>
public class GetFundAppBrandRedPacketBrandMerchantBatchByOutBatchNumberResponse : WechatTenpayResponse
{
public static class Types
{
public class TransferDetail
{
/// <summary>
/// 获取或设置商家明细单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("out_detail_no")]
[System.Text.Json.Serialization.JsonPropertyName("out_detail_no")]
public string OutDetailNumber { get; set; } = default!;
/// <summary>
/// 获取或设置微信明细单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("transfer_detail_no")]
[System.Text.Json.Serialization.JsonPropertyName("transfer_detail_no")]
public string DetailNumber { get; set; } = default!;
/// <summary>
/// 获取或设置明细状态。
/// </summary>
[Newtonsoft.Json.JsonProperty("detail_state")]
[System.Text.Json.Serialization.JsonPropertyName("detail_state")]
public string DetailState { get; set; } = default!;
}
}
/// <summary>
/// 获取或设置品牌微信商户号。
/// </summary>
[Newtonsoft.Json.JsonProperty("brand_mchid")]
[System.Text.Json.Serialization.JsonPropertyName("brand_mchid")]
public string BrandMerchantId { get; set; } = default!;
/// <summary>
/// 获取或设置品牌 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("brand_id")]
[System.Text.Json.Serialization.JsonPropertyName("brand_id")]
public int BrandId { get; set; }
/// <summary>
/// 获取或设置品牌微信 AppId。
/// </summary>
[Newtonsoft.Json.JsonProperty("brand_appid")]
[System.Text.Json.Serialization.JsonPropertyName("brand_appid")]
public string? BrandAppId { get; set; } = default!;
/// <summary>
/// 获取或设置品牌红包模板 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("template_id")]
[System.Text.Json.Serialization.JsonPropertyName("template_id")]
public string? TemplateId { get; set; }
/// <summary>
/// 获取或设置商家批次单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("out_batch_no")]
[System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
public string OutBatchNumber { get; set; } = default!;
/// <summary>
/// 获取或设置微信批次单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("batch_no")]
[System.Text.Json.Serialization.JsonPropertyName("batch_no")]
public string BatchNumber { get; set; } = default!;
/// <summary>
/// 获取或设置批次名称。
/// </summary>
[Newtonsoft.Json.JsonProperty("batch_name")]
[System.Text.Json.Serialization.JsonPropertyName("batch_name")]
public string BatchName { get; set; } = default!;
/// <summary>
/// 获取或设置批次状态。
/// </summary>
[Newtonsoft.Json.JsonProperty("batch_state")]
[System.Text.Json.Serialization.JsonPropertyName("batch_state")]
public string BatchState { get; set; } = default!;
/// <summary>
/// 获取或设置红包总金额(单位:分)。
/// </summary>
[Newtonsoft.Json.JsonProperty("total_amount")]
[System.Text.Json.Serialization.JsonPropertyName("total_amount")]
public int TotalAmount { get; set; }
/// <summary>
/// 获取或设置红包总笔数。
/// </summary>
[Newtonsoft.Json.JsonProperty("total_num")]
[System.Text.Json.Serialization.JsonPropertyName("total_num")]
public int TotalNumber { get; set; }
/// <summary>
/// 获取或设置发放成功金额(单位:分)。
/// </summary>
[Newtonsoft.Json.JsonProperty("success_amount")]
[System.Text.Json.Serialization.JsonPropertyName("success_amount")]
public int SuccessAmount { get; set; }
/// <summary>
/// 获取或设置发放成功笔数。
/// </summary>
[Newtonsoft.Json.JsonProperty("success_num")]
[System.Text.Json.Serialization.JsonPropertyName("success_num")]
public int SuccessNumber { get; set; }
/// <summary>
/// 获取或设置发放失败金额(单位:分)。
/// </summary>
[Newtonsoft.Json.JsonProperty("fail_amount")]
[System.Text.Json.Serialization.JsonPropertyName("fail_amount")]
public int FailAmount { get; set; }
/// <summary>
/// 获取或设置发放失败笔数。
/// </summary>
[Newtonsoft.Json.JsonProperty("fail_num")]
[System.Text.Json.Serialization.JsonPropertyName("fail_num")]
public int FailNumber { get; set; }
/// <summary>
/// 获取或设置批次备注。
/// </summary>
[Newtonsoft.Json.JsonProperty("batch_remark")]
[System.Text.Json.Serialization.JsonPropertyName("batch_remark")]
public string BatchRemark { get; set; } = default!;
/// <summary>
/// 获取或设置品牌红包明细列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("detail_list")]
[System.Text.Json.Serialization.JsonPropertyName("detail_list")]
public Types.TransferDetail[]? TransferDetailList { get; set; }
/// <summary>
/// 获取或设置创建时间。
/// </summary>
[Newtonsoft.Json.JsonProperty("create_time")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.Rfc3339DateTimeOffsetConverter))]
[System.Text.Json.Serialization.JsonPropertyName("create_time")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.Rfc3339DateTimeOffsetConverter))]
public DateTimeOffset CreateTime { get; set; }
/// <summary>
/// 获取或设置更新时间。
/// </summary>
[Newtonsoft.Json.JsonProperty("update_time")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.Rfc3339DateTimeOffsetConverter))]
[System.Text.Json.Serialization.JsonPropertyName("update_time")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.Rfc3339DateTimeOffsetConverter))]
public DateTimeOffset UpdateTime { get; set; }
/// <summary>
/// 获取或设置关闭原因。
/// </summary>
[Newtonsoft.Json.JsonProperty("close_reason")]
[System.Text.Json.Serialization.JsonPropertyName("close_reason")]
public string? Closeeason { get; set; }
}
}

View File

@ -0,0 +1,22 @@
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [GET] /fund-app/brand-redpacket/brand-merchant-batches/{batch_no}/details/{detail_no} 接口的请求。</para>
/// </summary>
public class GetFundAppBrandRedPacketBrandMerchantBatchDetailByDetailNumberRequest : WechatTenpayRequest
{
/// <summary>
/// 获取或设置微信批次单号。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string BatchNumber { get; set; } = string.Empty;
/// <summary>
/// 获取或设置微信明细单号。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string DetailNumber { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,10 @@
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [GET] /fund-app/brand-redpacket/brand-merchant-batches/{batch_no}/details/{detail_no} 接口的响应。</para>
/// </summary>
[WechatTenpaySensitive]
public class GetFundAppBrandRedPacketBrandMerchantBatchDetailByDetailNumberResponse : GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberResponse
{
}
}

View File

@ -0,0 +1,22 @@
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [GET] /fund-app/brand-redpacket/brand-merchant-out-batches/{out_batch_no}/out-details/{out_detail_no} 接口的请求。</para>
/// </summary>
public class GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberRequest : WechatTenpayRequest
{
/// <summary>
/// 获取或设置商家批次单号。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string OutBatchNumber { get; set; } = string.Empty;
/// <summary>
/// 获取或设置商家明细单号。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string OutDetailNumber { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,138 @@
using System;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [GET] /fund-app/brand-redpacket/brand-merchant-out-batches/{out_batch_no}/out-details/{out_detail_no} 接口的响应。</para>
/// </summary>
[WechatTenpaySensitive]
public class GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberResponse : WechatTenpayResponse
{
/// <summary>
/// 获取或设置品牌微信商户号。
/// </summary>
[Newtonsoft.Json.JsonProperty("brand_mchid")]
[System.Text.Json.Serialization.JsonPropertyName("brand_mchid")]
public string BrandMerchantId { get; set; } = default!;
/// <summary>
/// 获取或设置品牌 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("brand_id")]
[System.Text.Json.Serialization.JsonPropertyName("brand_id")]
public int BrandId { get; set; }
/// <summary>
/// 获取或设置品牌微信 AppId。
/// </summary>
[Newtonsoft.Json.JsonProperty("brand_appid")]
[System.Text.Json.Serialization.JsonPropertyName("brand_appid")]
public string? BrandAppId { get; set; } = default!;
/// <summary>
/// 获取或设置品牌红包模板 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("template_id")]
[System.Text.Json.Serialization.JsonPropertyName("template_id")]
public string? TemplateId { get; set; }
/// <summary>
/// 获取或设置商家批次单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("out_batch_no")]
[System.Text.Json.Serialization.JsonPropertyName("out_batch_no")]
public string OutBatchNumber { get; set; } = default!;
/// <summary>
/// 获取或设置微信批次单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("batch_no")]
[System.Text.Json.Serialization.JsonPropertyName("batch_no")]
public string BatchNumber { get; set; } = default!;
/// <summary>
/// 获取或设置商家明细单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("out_detail_no")]
[System.Text.Json.Serialization.JsonPropertyName("out_detail_no")]
public string OutDetailNumber { get; set; } = default!;
/// <summary>
/// 获取或设置微信明细单号。
/// </summary>
[Newtonsoft.Json.JsonProperty("detail_no")]
[System.Text.Json.Serialization.JsonPropertyName("detail_no")]
public string DetailNumber { get; set; } = default!;
/// <summary>
/// 获取或设置明细状态。
/// </summary>
[Newtonsoft.Json.JsonProperty("detail_state")]
[System.Text.Json.Serialization.JsonPropertyName("detail_state")]
public string DetailState { get; set; } = default!;
/// <summary>
/// 获取或设置红包金额(单位:分)。
/// </summary>
[Newtonsoft.Json.JsonProperty("amount")]
[System.Text.Json.Serialization.JsonPropertyName("amount")]
public int Amount { get; set; }
/// <summary>
/// 获取或设置红包备注。
/// </summary>
[Newtonsoft.Json.JsonProperty("remark")]
[System.Text.Json.Serialization.JsonPropertyName("remark")]
public string? Remark { get; set; }
/// <summary>
/// 获取或设置接收红包用户 OpenId。
/// </summary>
[Newtonsoft.Json.JsonProperty("openid")]
[System.Text.Json.Serialization.JsonPropertyName("openid")]
public string OpenId { get; set; } = default!;
/// <summary>
/// 获取或设置接收红包用户姓名(需使用商户私钥解密)。
/// </summary>
[Newtonsoft.Json.JsonProperty("user_name")]
[System.Text.Json.Serialization.JsonPropertyName("user_name")]
[WechatTenpaySensitiveProperty(scheme: Constants.SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256, algorithm: Constants.EncryptionAlgorithms.RSA_2048_ECB_PKCS8_OAEP_WITH_SHA1_AND_MGF1)]
[WechatTenpaySensitiveProperty(scheme: Constants.SignSchemes.WECHATPAY2_SM2_WITH_SM3, algorithm: Constants.EncryptionAlgorithms.SM2_C1C3C2_ASN1)]
public string? UserName { get; set; }
/// <summary>
/// 获取或设置创建时间。
/// </summary>
[Newtonsoft.Json.JsonProperty("create_time")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.Rfc3339DateTimeOffsetConverter))]
[System.Text.Json.Serialization.JsonPropertyName("create_time")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.Rfc3339DateTimeOffsetConverter))]
public DateTimeOffset CreateTime { get; set; }
/// <summary>
/// 获取或设置更新时间。
/// </summary>
[Newtonsoft.Json.JsonProperty("update_time")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.Rfc3339DateTimeOffsetConverter))]
[System.Text.Json.Serialization.JsonPropertyName("update_time")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.Rfc3339DateTimeOffsetConverter))]
public DateTimeOffset UpdateTime { get; set; }
/// <summary>
/// 获取或设置发起时间。
/// </summary>
[Newtonsoft.Json.JsonProperty("initiate_time")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.Rfc3339DateTimeOffsetConverter))]
[System.Text.Json.Serialization.JsonPropertyName("initiate_time")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.Rfc3339DateTimeOffsetConverter))]
public DateTimeOffset? InitiateTime { get; set; }
/// <summary>
/// 获取或设置失败原因。
/// </summary>
[Newtonsoft.Json.JsonProperty("fail_reason")]
[System.Text.Json.Serialization.JsonPropertyName("fail_reason")]
public string? FailReason { get; set; }
}
}

View File

@ -3,6 +3,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
/// <summary>
/// <para>表示 [GET] /fund-app/mch-transfer/transfer-bills/transfer-bill-no/{transfer_bill_no} 接口的响应。</para>
/// </summary>
[WechatTenpaySensitive]
public class GetFundAppMerchantTransferBillByTransferBillNumberResponse : GetFundAppMerchantTransferBillByOutBillNumberResponse
{
}

View File

@ -3,6 +3,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
/// <summary>
/// <para>表示 [POST] /fund-app/mch-transfer/transfer-to-qq-wallet-bills/{out_bill_no}/cancel 接口的响应。</para>
/// </summary>
[WechatTenpaySensitive]
public class CancelFundAppMerchantTransferToQQWalletBillResponse : GetFundAppMerchantTransferToQQWalletBillByOutBillNumberResponse
{
}

View File

@ -3,6 +3,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
/// <summary>
/// <para>表示 [POST] /fund-app/mch-transfer/transfer-to-qq-wallet-bills 接口的响应。</para>
/// </summary>
[WechatTenpaySensitive]
public class CreateFundAppMerchantTransferToQQWalletBillResponse : GetFundAppMerchantTransferToQQWalletBillByOutBillNumberResponse
{
}

View File

@ -3,6 +3,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
/// <summary>
/// <para>表示 [GET] /bank-transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id} 接口的响应。</para>
/// </summary>
[WechatTenpaySensitive]
public class GetBankTransferBatchDetailByDetailIdResponse : GetBankTransferBatchDetailByOutDetailNumberResponse
{
}

View File

@ -1,8 +1,9 @@
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [GET] /ecommerce/applyments/{applyment_id} 接口的响应。</para>
/// </summary>
[WechatTenpaySensitive]
public class GetEcommerceApplymentByApplymentIdResponse : GetEcommerceApplymentByOutRequestNumberResponse
{
}

View File

@ -1,8 +1,9 @@
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
{
/// <summary>
/// <para>表示 [GET] /partner-transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id} 接口的响应。</para>
/// </summary>
[WechatTenpaySensitive]
public class GetPartnerTransferBatchDetailByDetailIdResponse : GetPartnerTransferBatchDetailByOutDetailNumberResponse
{
}

View File

@ -0,0 +1,20 @@
{
"brand_id": 1234,
"brand_appid": "wxf636efh567hg4356",
"scene": "CUSTOM_SEND",
"template_id": "123400001",
"out_batch_no": "plfk2020042013",
"batch_name": "双十一营销用品牌红包",
"batch_remark": "双十一营销用品牌红包",
"total_amount": 10000,
"total_num": 10,
"detail_list": [
{
"out_detail_no": "x23zy545Bd5436",
"amount": 100,
"openid": "o-MYE42l80oelYMDE34nYD456Xoy",
"user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
"remark": "来自XX的红包"
}
]
}

View File

@ -0,0 +1,6 @@
{
"out_batch_no": "plfk2020042013",
"batch_no": "1210000071100999991182020050700019480001",
"create_time": "2015-05-20T13:29:35+08:00",
"batch_state": "ACCEPTED"
}

View File

@ -0,0 +1,27 @@
{
"brand_mchid": "1900001109",
"batch_no": "1030000071100999991182020050700019480001",
"out_batch_no": "plfk2020042013",
"brand_id": 1234,
"template_id": "12340000000001",
"brand_appid": "wxf636efh567hg4356",
"batch_state": "ACCEPTED",
"batch_name": "双十一营销发放品牌红包",
"batch_remark": "双十一营销发放品牌红包",
"close_reason": "SYSTEM_OVERDUE_CLOSE",
"total_amount": 10000,
"total_num": 10,
"create_time": "2015-05-20T13:29:35+08:00",
"update_time": "2015-05-20T13:29:35+08:00",
"success_amount": 5000,
"success_num": 10,
"fail_amount": 5000,
"fail_num": 10,
"detail_list": [
{
"transfer_detail_no": "1220000071100999991182020050700019500100",
"out_detail_no": "x23zy545Bd5436",
"detail_state": "DETAIL_SUCCESS"
}
]
}

View File

@ -0,0 +1,27 @@
{
"brand_mchid": "1900001109",
"batch_no": "1030000071100999991182020050700019480001",
"out_batch_no": "plfk2020042013",
"brand_id": 1234,
"template_id": "12340000000001",
"brand_appid": "wxf636efh567hg4356",
"batch_state": "ACCEPTED",
"batch_name": "双十一营销发放品牌红包",
"batch_remark": "双十一营销发放品牌红包",
"close_reason": "SYSTEM_OVERDUE_CLOSE",
"total_amount": 10000,
"total_num": 10,
"create_time": "2015-05-20T13:29:35+08:00",
"update_time": "2015-05-20T13:29:35+08:00",
"success_amount": 5000,
"success_num": 10,
"fail_amount": 5000,
"fail_num": 10,
"detail_list": [
{
"transfer_detail_no": "1220000071100999991182020050700019500100",
"out_detail_no": "x23zy545Bd5436",
"detail_state": "DETAIL_SUCCESS"
}
]
}

View File

@ -0,0 +1,18 @@
{
"brand_mchid": "1900001109",
"out_batch_no": "plfk2020042013",
"batch_no": "1030000071100999991182020050700019480001",
"out_detail_no": "x23zy545Bd5436",
"detail_no": "1040000071100999991182020050700019500100",
"detail_state": "DETAIL_SUCCESS",
"amount": 100,
"remark": "来自XX品牌红包",
"fail_reason": "ACCOUNT_FROZEN",
"openid": "o-MYE42l80oelYMDE34nYD456Xoy",
"user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
"initiate_time": "2015-05-20T13:29:35+08:00",
"update_time": "2015-05-20T13:29:35+08:00",
"brand_id": 1234,
"template_id": "12340000000001",
"brand_appid": "wxf636efh567hg4356"
}

View File

@ -0,0 +1,18 @@
{
"brand_mchid": "1900001109",
"out_batch_no": "plfk2020042013",
"batch_no": "1030000071100999991182020050700019480001",
"out_detail_no": "x23zy545Bd5436",
"detail_no": "1040000071100999991182020050700019500100",
"detail_state": "DETAIL_SUCCESS",
"amount": 100,
"remark": "来自XX品牌红包",
"fail_reason": "ACCOUNT_FROZEN",
"openid": "o-MYE42l80oelYMDE34nYD456Xoy",
"user_name": "757b340b45ebef5467rter35gf464344v3542sdf4t6re4tb4f54ty45t4yyry45",
"initiate_time": "2015-05-20T13:29:35+08:00",
"update_time": "2015-05-20T13:29:35+08:00",
"brand_id": 1234,
"template_id": "12340000000001",
"brand_appid": "wxf636efh567hg4356"
}

View File

@ -907,6 +907,65 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
}
}
[Fact(DisplayName = "测试用例:加密请求中的敏感数据([POST] /fund-app/brand-redpacket/brand-merchant-batches")]
public async Task TestEncryptRequestSensitiveProperty_CreateFundAppBrandRedPacketBrandMerchantBatchRequest()
{
static Models.CreateFundAppBrandRedPacketBrandMerchantBatchRequest GenerateMockRequestModel()
{
return new Models.CreateFundAppBrandRedPacketBrandMerchantBatchRequest()
{
TransferDetailList = new List<Models.CreateFundAppBrandRedPacketBrandMerchantBatchRequest.Types.TransferDetail>()
{
new Models.CreateFundAppBrandRedPacketBrandMerchantBatchRequest.Types.TransferDetail()
{
UserName = MOCK_PLAIN_STR
}
}
};
}
static void AssertMockRequestModel(Models.CreateFundAppBrandRedPacketBrandMerchantBatchRequest request, Func<string, string> decryptor)
{
Assert.NotEqual(MOCK_PLAIN_STR, request.TransferDetailList![0].UserName!);
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.TransferDetailList![0].UserName!));
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
}
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
{
using (var client = CreateMockClientUseRSA(autoEncrypt: false))
{
var request = GenerateMockRequestModel();
client.EncryptRequestSensitiveProperty(request);
AssertMockRequestModel(request, (cipher) => Utilities.RSAUtility.DecryptWithECB(RSA_PEM_PRIVATE_KEY, (EncodedString)cipher)!);
}
using (var client = CreateMockClientUseRSA(autoEncrypt: true))
{
var request = GenerateMockRequestModel();
await client.ExecuteCreateFundAppBrandRedPacketBrandMerchantBatchAsync(request);
AssertMockRequestModel(request, (cipher) => Utilities.RSAUtility.DecryptWithECB(RSA_PEM_PRIVATE_KEY, (EncodedString)cipher)!);
}
}
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantSM2CertificatePrivateKey))
{
using (var client = CreateMockClientUseSM2(autoEncrypt: false))
{
var request = GenerateMockRequestModel();
client.EncryptRequestSensitiveProperty(request);
AssertMockRequestModel(request, (cipher) => Utilities.SM2Utility.Decrypt(SM2_PEM_PRIVATE_KEY, (EncodedString)cipher)!);
}
using (var client = CreateMockClientUseSM2(autoEncrypt: true))
{
var request = GenerateMockRequestModel();
await client.ExecuteCreateFundAppBrandRedPacketBrandMerchantBatchAsync(request);
AssertMockRequestModel(request, (cipher) => Utilities.SM2Utility.Decrypt(SM2_PEM_PRIVATE_KEY, (EncodedString)cipher)!);
}
}
}
[Fact(DisplayName = "测试用例:加密请求中的敏感数据([POST] /marketing/membercard-open/cards/{card_id}/phone-membercard/import")]
public async Task TestEncryptRequestSensitiveProperty_ImportMarketingMemberCardOpenCardPhoneRequest()
{

View File

@ -553,6 +553,67 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
}
}
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /fund-app/mch-transfer/transfer-to-qq-wallet-bills/{out_bill_no}")]
public async Task TestDecryptResponseSensitiveProperty_GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberResponse()
{
static Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberResponse GenerateMockResponseModel(Func<string, string> encryptor)
{
return SetMockResponseRawStatusAsOk(new Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberResponse()
{
UserName = encryptor.Invoke(MOCK_PLAIN_STR)
});
}
static void AssertMockResponseModel(Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberResponse response)
{
Assert.Equal(MOCK_PLAIN_STR, response.UserName!);
}
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
{
using (var client = CreateMockClientUseRSA(autoDecrypt: false))
{
var response = GenerateMockResponseModel((plain) => Utilities.RSAUtility.EncryptWithECBByCertificate(RSA_PEM_CERTIFICATE, plain)!);
client.DecryptResponseSensitiveProperty(response);
AssertMockResponseModel(response);
}
using (var client = CreateMockClientUseRSA(
autoDecrypt: true,
mockResponseContent: new SystemTextJsonSerializer().Serialize(
GenerateMockResponseModel((plain) => Utilities.RSAUtility.EncryptWithECBByCertificate(RSA_PEM_CERTIFICATE, plain)!)
)
))
{
var request = new Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberRequest();
var response = await client.ExecuteGetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberAsync(request);
AssertMockResponseModel(response);
}
}
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantSM2CertificatePrivateKey))
{
using (var client = CreateMockClientUseSM2(autoDecrypt: false))
{
var response = GenerateMockResponseModel((plain) => Utilities.SM2Utility.EncryptByCertificate(SM2_PEM_CERTIFICATE, plain)!);
client.DecryptResponseSensitiveProperty(response);
AssertMockResponseModel(response);
}
using (var client = CreateMockClientUseSM2(
autoDecrypt: true,
mockResponseContent: new SystemTextJsonSerializer().Serialize(
GenerateMockResponseModel((plain) => Utilities.SM2Utility.EncryptByCertificate(SM2_PEM_CERTIFICATE, plain)!)
)
))
{
var request = new Models.GetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberRequest();
var response = await client.ExecuteGetFundAppBrandRedPacketBrandMerchantBatchDetailByOutDetailNumberAsync(request);
AssertMockResponseModel(response);
}
}
}
[Fact(DisplayName = "测试用例:解密响应中的敏感数据([GET] /marketing/shopping-receipt/shoppingreceipts")]
public async Task TestDecryptResponseSensitiveProperty_UploadMarketingShoppingReceiptResponse()
{