Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wechatpay v3 jspayment #106

Merged
merged 3 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 24 additions & 30 deletions docs/WeChatPay.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ public override void ConfigureServices (ServiceConfigurationContext context)
{
// 默认商户 Id
op.MchId = "000000000000000";
// 微信支付的 API 密钥信息,会在后续进行签名时被使用
op.ApiKey = "****************************";
// 微信支付的 API V3 密钥信息,会在后续进行 签名/加密/解密 时被使用
op.ApiV3Key = "****************************";
// 支付结果回调地址,用于接收支付结果通知。
// 如果安装了本模块提供的 HttpApi 模块,则默认是 域名 + /wechat-pay/notify 路由。
op.NotifyUrl = "https://xxx.xxxx.com/wechat-pay/notify";

// 如果需要支持退款操作,则以下配置必须

// 退款结果回调地址,用于接收退款结果通知。
Expand All @@ -54,7 +54,7 @@ public override void ConfigureServices (ServiceConfigurationContext context)

完整的 Setting 项清单:https://github.com/EasyAbp/Abp.WeChat/blob/master/src/Pay/EasyAbp.Abp.WeChat.Pay/Settings/AbpWeChatPaySettingDefinitionProvider.cs

> 注意,如您在 appsettings.json 中通过 Setting 设置 `ApiKey` 或 `CertificateSecret`,须自行加密后填入,参考:https://docs.abp.io/en/abp/latest/String-Encryption
> 注意,如您在 appsettings.json 中通过 Setting 设置 `ApiV3Key` 或 `CertificateSecret`,须自行加密后填入,参考:https://docs.abp.io/en/abp/latest/String-Encryption

## 二、提供的回调接口

Expand All @@ -65,17 +65,16 @@ public override void ConfigureServices (ServiceConfigurationContext context)
用户如果需要对支付结果进行处理,只需要实现一个或多个 `IWeChatPayEventHandler` 处理器即可。当框架接受到微信通知时,会触发开发人员编写的处理器,并将微信结果传递给这些处理器。

```csharp
public class WeChatPaymentHandler : IWeChatPayEventHandler
{
// 定义当前的处理的事件类型为:支付成功事件
public WeChatHandlerType Type => WeChatHandlerType.Paid;

public async Task<WeChatRequestHandlingResult> HandleAsync(WeChatPayEventModel model)
{
Console.WriteLine("我知道支付成功了");
return new WeChatRequestHandlingResult(true);
}
}
public class PaidWeChatPayEventHandler : IWeChatPayEventHandler<QueryOrderResponse>
{
public WeChatHandlerType Type => WeChatHandlerType.Paid;

public Task<WeChatRequestHandlingResult> HandleAsync(WeChatPayEventModel<QueryOrderResponse> model)
{
Console.WriteLine("支付成功。");
return Task.FromResult(new WeChatRequestHandlingResult(true));
}
}
```

编写完成之后,则需要开发人员手动注入这些处理器。
Expand All @@ -92,8 +91,6 @@ public class XXXDomainModule : AbpModule

如果在处理过程当中出现了异常,那么你可以在返回 `WeChatRequestHandlingResult` 对象时,设置 `success` 参数为 `false`,并且可以填写对应的失败原因。

其中 `XmlDocument` 对象内部的参数含义,可以参考微信支付 **[开发文档](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8)**。

WeChatPay 模块默认提供了参数校验处理器,各个处理器的调用顺序是按照 **注入顺序** 来的,目前暂时不支持处理器自定义排序。

### 2.2 退款回调接口
Expand All @@ -103,17 +100,16 @@ WeChatPay 模块默认提供了参数校验处理器,各个处理器的调用
用户如果需要对退款通知进行处理,只需要实现一个或多个 `IWeChatPayEventHandler` 处理器即可。当框架接受到微信通知时,会触发开发人员编写的处理器,并将微信结果传递给这些处理器。

```csharp
public class XXXAAAHandler : IWeChatPayEventHandler
{
// 定义当前处理器的类型为退款。
public WeChatHandlerType Type => WeChatHandlerType.Refund;

public Task HandleAsync(XmlDocument xmlDocument)
{
Console.WriteLine("接受到了数据");
return Task.CompletedTask;
}
}
public class RefundWeChatPayEventHandler : IWeChatPayEventHandler<RefundOrderResponse>
{
public WeChatHandlerType Type => WeChatHandlerType.Refund;

public Task<WeChatRequestHandlingResult> HandleAsync(WeChatPayEventModel<RefundOrderResponse> model)
{
Console.WriteLine("退款成功。");
return Task.FromResult(new WeChatRequestHandlingResult(true));
}
}
```

编写完成之后,则需要开发人员手动注册这些处理器。
Expand All @@ -128,8 +124,6 @@ public class XXXDomainModule : AbpModule
}
```

其中 `XmlDocument` 对象内部的参数含义,可以参考微信支付 **[开发文档](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_16&index=10)**。

## 三、服务的使用

### 3.1 发起支付请求
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ namespace EasyAbp.Abp.WeChat.Pay.RequestHandling
/// <summary>
/// 定义了微信支付回调处理器。
/// </summary>
public interface IWeChatPayEventHandler
public interface IWeChatPayEventHandler<TResource>
{
WeChatHandlerType Type { get; }

Task<WeChatRequestHandlingResult> HandleAsync<TResource>(WeChatPayEventModel<TResource> model);
Task<WeChatRequestHandlingResult> HandleAsync(WeChatPayEventModel<TResource> model);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public virtual async Task<WeChatRequestHandlingResult> PaidNotifyAsync(NotifyInp
return new WeChatRequestHandlingResult(false, "签名验证不通过");
}

var handlers = LazyServiceProvider.LazyGetService<IEnumerable<IWeChatPayEventHandler>>()
var handlers = LazyServiceProvider.LazyGetService<IEnumerable<IWeChatPayEventHandler<QueryOrderResponse>>>()
.Where(h => h.Type == WeChatHandlerType.Paid);

var decryptingResult = DecryptResource<QueryOrderResponse>(input, options);
Expand Down Expand Up @@ -70,7 +70,7 @@ public virtual async Task<WeChatRequestHandlingResult> RefundNotifyAsync(NotifyI
return new WeChatRequestHandlingResult(false, "签名验证不通过");
}

var handlers = LazyServiceProvider.LazyGetService<IEnumerable<IWeChatPayEventHandler>>()
var handlers = LazyServiceProvider.LazyGetService<IEnumerable<IWeChatPayEventHandler<RefundOrderResponse>>>()
.Where(x => x.Type == WeChatHandlerType.Refund);

var decryptingResult = DecryptResource<RefundOrderResponse>(input, options);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
namespace EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.AppPayment;
using System.Net.Http;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Pay.Options;
using EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.Models;
using Volo.Abp.DependencyInjection;

public class AppPaymentService
namespace EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.AppPayment;

public class AppPaymentService : BasicPaymentService
{

public const string CreateOrderUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";

public AppPaymentService(AbpWeChatPayOptions options,
IAbpLazyServiceProvider lazyServiceProvider) : base(options,
lazyServiceProvider)
{
}

public Task<CreateOrderResponse> CreateOrderAsync(CreateOrderRequest request)
{
return ApiRequester.RequestAsync<CreateOrderResponse>(HttpMethod.Post, CreateOrderUrl, request);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Pay.Options;
using EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.JSPayment.Models;
using EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.Models;
using EasyAbp.Abp.WeChat.Pay.Services.ParametersModel;
using Volo.Abp.DependencyInjection;

namespace EasyAbp.Abp.WeChat.Pay.Services.BasicPayment;

public class BasicPaymentService : WeChatPayServiceBase
{
public const string QueryOrderByWechatNumberUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id}";
public const string QueryOrderByOutTradeNumberUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}";
public const string CloseOrderUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}/close";
public const string RefundUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
public const string QueryRefundOrderUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{out_refund_no}";
public const string GetTransactionBillUrl = "https://api.mch.weixin.qq.com/v3/bill/tradebill";
public const string GetFundFlowBillUrl = "https://api.mch.weixin.qq.com/v3/bill/fundflowbill";

public BasicPaymentService(AbpWeChatPayOptions options,
IAbpLazyServiceProvider lazyServiceProvider) : base(options,
lazyServiceProvider)
{
}

public Task<QueryOrderResponse> QueryOrderByWechatNumberAsync(QueryOrderByWechatNumberRequest request)
{
var requestUrl = QueryOrderByWechatNumberUrl.Replace("{transaction_id}", request.TransactionId);
return ApiRequester.RequestAsync<QueryOrderResponse>(HttpMethod.Get, requestUrl, request);
}

public Task<QueryOrderResponse> QueryOrderByOutTradeNumberAsync(QueryOrderByOutTradeNumberRequest request)
{
var requestUrl = QueryOrderByOutTradeNumberUrl.Replace("{out_trade_no}", request.OutTradeNo);
return ApiRequester.RequestAsync<QueryOrderResponse>(HttpMethod.Get, requestUrl, request);
}

public Task<WeChatPayCommonErrorResponse> CloseOrderAsync(CloseOrderRequest request)
{
var requestUrl = CloseOrderUrl.Replace("{out_trade_no}", request.OutTradeNo);
return ApiRequester.RequestAsync<WeChatPayCommonErrorResponse>(HttpMethod.Post, requestUrl, request);
}

public Task<RefundOrderResponse> RefundAsync(RefundOrderRequest orderRequest)
{
return ApiRequester.RequestAsync<RefundOrderResponse>(HttpMethod.Post, RefundUrl, orderRequest);
}

public Task<RefundOrderResponse> QueryRefundOrderAsync(QueryRefundOrderRequest request)
{
var requestUrl = QueryRefundOrderUrl.Replace("{out_refund_no}", request.OutRefundNo);
return ApiRequester.RequestAsync<RefundOrderResponse>(HttpMethod.Get, requestUrl);
}

public Task<GetBillResponse> GetTransactionBillAsync(GetTransactionBillRequest request)
{
return ApiRequester.RequestAsync<GetBillResponse>(HttpMethod.Get, GetTransactionBillUrl, request);
}

public Task<GetBillResponse> GetFundFlowBillAsync(GetFundFlowBillRequest request)
{
return ApiRequester.RequestAsync<GetBillResponse>(HttpMethod.Get, GetFundFlowBillUrl, request);
}

public async Task<Stream> DownloadBillFileAsync(string billDownloadUrl)
{
return await (await ApiRequester.RequestRawAsync(HttpMethod.Get, billDownloadUrl)).Content.ReadAsStreamAsync();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
namespace EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.H5Payment;
using System.Net.Http;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Pay.Options;
using EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.Models;
using Volo.Abp.DependencyInjection;

public class H5PaymentService
namespace EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.H5Payment;

public class H5PaymentService : BasicPaymentService
{

public const string CreateOrderUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/h5";

public H5PaymentService(AbpWeChatPayOptions options,
IAbpLazyServiceProvider lazyServiceProvider) : base(options,
lazyServiceProvider)
{
}

public Task<CreateOrderResponse> CreateOrderAsync(CreateOrderRequest request)
{
return ApiRequester.RequestAsync<CreateOrderResponse>(HttpMethod.Post, CreateOrderUrl, request);
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
using System.IO;
using System.Net.Http;
using System.Net.Http;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Pay.Options;
using EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.JSPayment.Models;
using EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.Models;
using EasyAbp.Abp.WeChat.Pay.Services.ParametersModel;
using Volo.Abp.DependencyInjection;
using CreateOrderRequest = EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.JSPayment.Models.CreateOrderRequest;

namespace EasyAbp.Abp.WeChat.Pay.Services.BasicPayment.JSPayment;

public class JsPaymentService : WeChatPayServiceBase
public class JsPaymentService : BasicPaymentService
{
public const string CreateOrderUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
public const string QueryOrderByWechatNumberUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id}";
public const string QueryOrderByOutTradeNumberUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}";
public const string CloseOrderUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}/close";
public const string RefundUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
public const string QueryRefundOrderUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{out_refund_no}";
public const string GetTransactionBillUrl = "https://api.mch.weixin.qq.com/v3/bill/tradebill";
public const string GetFundFlowBillUrl = "https://api.mch.weixin.qq.com/v3/bill/fundflowbill";

public JsPaymentService(AbpWeChatPayOptions options,
IAbpLazyServiceProvider lazyServiceProvider) : base(options,
Expand All @@ -31,48 +21,4 @@ public Task<CreateOrderResponse> CreateOrderAsync(CreateOrderRequest request)
{
return ApiRequester.RequestAsync<CreateOrderResponse>(HttpMethod.Post, CreateOrderUrl, request);
}

public Task<QueryOrderResponse> QueryOrderByWechatNumberAsync(QueryOrderByWechatNumberRequest request)
{
var requestUrl = QueryOrderByWechatNumberUrl.Replace("{transaction_id}", request.TransactionId);
return ApiRequester.RequestAsync<QueryOrderResponse>(HttpMethod.Get, requestUrl, request);
}

public Task<QueryOrderResponse> QueryOrderByOutTradeNumberAsync(QueryOrderByOutTradeNumberRequest request)
{
var requestUrl = QueryOrderByOutTradeNumberUrl.Replace("{out_trade_no}", request.OutTradeNo);
return ApiRequester.RequestAsync<QueryOrderResponse>(HttpMethod.Get, requestUrl, request);
}

public Task<WeChatPayCommonErrorResponse> CloseOrderAsync(CloseOrderRequest request)
{
var requestUrl = CloseOrderUrl.Replace("{out_trade_no}", request.OutTradeNo);
return ApiRequester.RequestAsync<WeChatPayCommonErrorResponse>(HttpMethod.Post, requestUrl, request);
}

public Task<RefundOrderResponse> RefundAsync(RefundOrderRequest orderRequest)
{
return ApiRequester.RequestAsync<RefundOrderResponse>(HttpMethod.Post, RefundUrl, orderRequest);
}

public Task<RefundOrderResponse> QueryRefundOrderAsync(QueryRefundOrderRequest request)
{
var requestUrl = QueryRefundOrderUrl.Replace("{out_refund_no}", request.OutRefundNo);
return ApiRequester.RequestAsync<RefundOrderResponse>(HttpMethod.Get, requestUrl);
}

public Task<GetBillResponse> GetTransactionBillAsync(GetTransactionBillRequest request)
{
return ApiRequester.RequestAsync<GetBillResponse>(HttpMethod.Get, GetTransactionBillUrl, request);
}

public Task<GetBillResponse> GetFundFlowBillAsync(GetFundFlowBillRequest request)
{
return ApiRequester.RequestAsync<GetBillResponse>(HttpMethod.Get, GetFundFlowBillUrl, request);
}

public async Task<Stream> DownloadBillFileAsync(string billDownloadUrl)
{
return await (await ApiRequester.RequestRawAsync(HttpMethod.Get, billDownloadUrl)).Content.ReadAsStreamAsync();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,22 @@ public class CreateOrderRequest : BasicPayment.Models.CreateOrderRequest
[NotNull]
[JsonProperty("payer")]
public CreateOrderPayerModel Payer { get; set; }

public class CreateOrderPayerModel
{
/// <summary>
/// 用户标识。
/// </summary>
/// <remarks>
/// 用户在直连商户 AppId 下的唯一标识。<br/>
/// 下单前需获取到用户的 OpenId。
/// </remarks>
/// <example>
/// 示例值: oUpF8uMuAJO_M2pxb1Q9zNjWeS6o。
/// </example>
[Required]
[StringLength(128, MinimumLength = 1)]
[JsonProperty("openid")]
public string OpenId { get; set; }
}
}