Skip to content

Commit

Permalink
Merge pull request #106 from EasyAbp/wechatpay-v3-jspayment
Browse files Browse the repository at this point in the history
Wechatpay v3 jspayment
  • Loading branch information
real-zony authored Jan 15, 2024
2 parents 3b4266a + a6e0a70 commit 9679db8
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 124 deletions.
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; }
}
}
Loading

0 comments on commit 9679db8

Please sign in to comment.