diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMarketingBankExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMarketingBankExtensions.cs
new file mode 100644
index 00000000..64158a24
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteMarketingBankExtensions.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Web;
+using Flurl;
+using Flurl.Http;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
+{
+ ///
+ /// 为 提供银行定向促活相关的 API 扩展方法。
+ ///
+ public static class WechatTenpayClientExecuteMarketingBankExtensions
+ {
+ ///
+ /// 异步调用 [POST] /marketing/bank/packages/{package_id}/tasks 接口。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_8_1.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter9_8_1.shtml
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteUploadMarketingBankPackagesTasksAsync(this WechatTenpayClient client, Models.UploadMarketingBankPackagesTasksRequest request, CancellationToken cancellationToken = default)
+ {
+ if (client is null) throw new ArgumentNullException(nameof(client));
+ if (request is null) throw new ArgumentNullException(nameof(request));
+
+ if (string.IsNullOrEmpty(request.FileName))
+ request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".txt";
+
+ if (string.IsNullOrEmpty(request.FileHash))
+ request.FileHash = Security.SHA256Utility.Hash(request.FileBytes).ToLower();
+
+ if (string.IsNullOrEmpty(request.FileContentType))
+ request.FileContentType = Utilities.FileNameToContentTypeMapper.GetContentTypeForImage(request.FileName!) ?? "text/plain";
+
+ IFlurlRequest flurlReq = client
+ .CreateRequest(request, HttpMethod.Post, "marketing", "bank", "packages", request.PackageId, "tasks");
+
+ string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
+ using var fileContent = new ByteArrayContent(request.FileBytes);
+ using var metaContent = new ByteArrayContent(Encoding.UTF8.GetBytes(client.JsonSerializer.Serialize(request)));
+ using var httpContent = new MultipartFormDataContent(boundary);
+ httpContent.Add(metaContent, $"\"{Constants.FormDataFields.FORMDATA_META}\"");
+ httpContent.Add(fileContent, "\"file\"", $"\"{HttpUtility.UrlEncode(request.FileName)}\"");
+ httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary);
+ metaContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
+ fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(request.FileContentType);
+
+ return await client.SendRequestAsync(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
+ }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MarketingBank/UploadMarketingBankPackagesTasksRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MarketingBank/UploadMarketingBankPackagesTasksRequest.cs
new file mode 100644
index 00000000..f3258aeb
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MarketingBank/UploadMarketingBankPackagesTasksRequest.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [POST] /marketing/bank/packages/{package_id}/tasks 接口的请求。
+ ///
+ public class UploadMarketingBankPackagesTasksRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置号码包 ID。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string PackageId { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置任务上传字节数组。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public byte[] FileBytes { get; set; } = new byte[0];
+
+ ///
+ /// 获取或设置任务上传文件名。如果不指定将由系统自动生成。
+ ///
+ [Newtonsoft.Json.JsonProperty("filename")]
+ [System.Text.Json.Serialization.JsonPropertyName("filename")]
+ public string? FileName { get; set; }
+
+ ///
+ /// 获取或设置任务上传文件摘要。如果不指定将由系统自动生成。
+ ///
+ [Newtonsoft.Json.JsonProperty("sha256")]
+ [System.Text.Json.Serialization.JsonPropertyName("sha256")]
+ public string? FileHash { get; set; }
+
+ ///
+ /// 获取或设置任务上传文件 Conent-Type。如果不指定将由系统自动生成。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string? FileContentType { get; set; }
+
+ ///
+ /// 获取或设置银行类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("bank_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("bank_type")]
+ public string? BankType { get; set; }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MarketingBank/UploadMarketingBankPackagesTasksResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MarketingBank/UploadMarketingBankPackagesTasksResponse.cs
new file mode 100644
index 00000000..09e6c1e8
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/MarketingBank/UploadMarketingBankPackagesTasksResponse.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [POST] /marketing/bank/packages/{package_id}/tasks 接口的响应。
+ ///
+ public class UploadMarketingBankPackagesTasksResponse : WechatTenpayResponse
+ {
+ ///
+ /// 获取或设置任务上传的文件名。
+ ///
+ [Newtonsoft.Json.JsonProperty("filename")]
+ [System.Text.Json.Serialization.JsonPropertyName("filename")]
+ public string FileName { get; set; } = default!;
+
+ ///
+ /// 获取或设置上传任务 ID。
+ ///
+ [Newtonsoft.Json.JsonProperty("task_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("task_id")]
+ public string TaskId { get; set; } = default!;
+
+ ///
+ /// 获取或设置号码包 ID。
+ ///
+ [Newtonsoft.Json.JsonProperty("package_id")]
+ [System.Text.Json.Serialization.JsonPropertyName("package_id")]
+ public string PackageId { get; set; } = default!;
+
+ ///
+ /// 获取或设置任务状态。
+ ///
+ [Newtonsoft.Json.JsonProperty("status")]
+ [System.Text.Json.Serialization.JsonPropertyName("status")]
+ public string? Status { get; set; }
+
+ ///
+ /// 获取或设置银行类型。
+ ///
+ [Newtonsoft.Json.JsonProperty("bank_type")]
+ [System.Text.Json.Serialization.JsonPropertyName("bank_type")]
+ public string? BankType { get; set; }
+
+ ///
+ /// 获取或设置匹配成功的协议号数。
+ ///
+ [Newtonsoft.Json.JsonProperty("success_count")]
+ [System.Text.Json.Serialization.JsonPropertyName("success_count")]
+ public int? SuccessCount { get; set; }
+
+ ///
+ /// 获取或设置匹配失败的协议号数。
+ ///
+ [Newtonsoft.Json.JsonProperty("fail_count")]
+ [System.Text.Json.Serialization.JsonPropertyName("fail_count")]
+ public int? FailCount { get; set; }
+
+ ///
+ /// 获取或设置匹配成功的微信用户数。
+ ///
+ [Newtonsoft.Json.JsonProperty("success_user_count")]
+ [System.Text.Json.Serialization.JsonPropertyName("success_user_count")]
+ public int? SuccessUserCount { 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; }
+ }
+}