由于精力有限,在项目初期没有完成所有微信支付 V3 接口的封装,这个时候你可以自己继承 WeChatPayServiceBase
基类,并直接使用基类提供的 ApiRequester
属性发起微信支付 V3 接口的请求。
所有的证书管理和签名验证都已经实现,你只需要自己编写对应的请求体对象和响应对象的类型定义。
你可以参考以下代码:
using System.Net.Http;
using System.Threading.Tasks;
using EasyAbp.Abp.WeChat.Pay.Options;
using EasyAbp.Abp.WeChat.Pay.Services.MarketingTools.VoucherService.ParametersModel;
using Volo.Abp.DependencyInjection;
namespace EasyAbp.Abp.WeChat.Pay.Services.MarketingTools.VoucherService;
/// <summary>
/// 代金券服务。
/// </summary>
public class VoucherWeService : WeChatPayServiceBase
{
public const string CreateCouponBatchUrl = "https://api.mch.weixin.qq.com/v3/marketing/favor/coupon-stocks";
public VoucherWeService(AbpWeChatPayOptions options,
IAbpLazyServiceProvider lazyServiceProvider) : base(options,
lazyServiceProvider)
{
}
public Task<CreateCouponBatchResponse> CreateCouponBatchAsync(CreateCouponBatchRequest request)
{
return ApiRequester.RequestAsync<CreateCouponBatchResponse>(HttpMethod.Post, CreateCouponBatchUrl, request, MchId);
}
}
服务 | 支持情况 | 备注 |
---|---|---|
JSAPI 支付 | ||
APP 支付 | ||
H5 支付 | ||
Native 支付 | ||
小程序支付 | ||
合单支付 | ||
付款码支付 | 付款码支付仍然使用的是 微信支付 V2 版本的 API。 目前不考虑再支持此支付方式,请考虑使用 Native 支付替代。 |
TODO
TODO
TODO
TODO
TODO
TODO
添加 EasyAbp.Abp.WeChat.Pay 模块的 NuGet 包或者项目引用到 Domain 层,并在对应的模块上面添加 [DependsOn]
特性标签。
[DependsOn(typeof(AbpWeChatPayModule))]
public class XXXDomainModule : AbpModule
{
}
添加 EasyAbp.Abp.WeChat.Pay.HttpApi 模块的 NuGet 包或者项目引用到 Http.Api 层,并在对应的模块上面添加 [DependsOn]
特性标签。
[DependsOn(typeof(AbpWeChatPayHttpApiModule))]
public class XXXHttpApiModule : AbpModule
{
}
本模块的默认配置参数使用 ABP Setting 设施管理,在 Setting 的值未提供时,由 AbpWeChatPayOptions
进行补充。如果您的应用只使用单个微信支付商户,只需在启动模块的 ConfigureService()
方法中进行配置即可:
public override void ConfigureServices (ServiceConfigurationContext context)
{
Configure<AbpWeChatPayOptions> (op =>
{
// 默认商户 Id
op.MchId = "000000000000000";
// 微信支付的 API V3 密钥信息,会在后续进行 签名/加密/解密 时被使用。
op.ApiV3Key = "****************************";
// 支付结果回调地址,用于接收支付结果通知。
// 如果安装了本模块提供的 HttpApi 模块,则默认是 域名 + /wechat-pay/notify 路由。
op.NotifyUrl = "https://xxx.xxxx.com/wechat-pay/notify";
// 如果需要支持退款操作,则以下配置必须
// 退款结果回调地址,用于接收退款结果通知。
// 如果安装了本模块提供的 HttpApi 模块,则默认是 域名 + /wechat-pay/refund-notify 路由。
op.RefundNotifyUrl = "https://xxx.xxxx.com/wechat-pay/refund-notify";
// 存放微信支付API证书的BLOB容器名,参考:https://docs.abp.io/en/abp/latest/Blob-Storing
op.CertificateBlobContainerName = "MyBlobContainer";
// 存放微信支付API证书的BLOB名称
op.CertificateBlobName = "WeChatPayCert";
// 微信支付API证书秘钥,默认为商户名
op.CertificateSecret = "000000000000000";
});
}
完整的 Setting 项清单:https://github.com/EasyAbp/Abp.WeChat/blob/master/src/Pay/EasyAbp.Abp.WeChat.Pay/Settings/AbpWeChatPaySettingDefinitionProvider.cs
注意,如您在 appsettings.json 中通过 Setting 设置
ApiV3Key
或CertificateSecret
,须自行加密后填入,参考:https://docs.abp.io/en/abp/latest/String-Encryption
支付通知接口的默认路由是 /wechat-pay/notify
。当开发人员调用了统一下单接口之后,微信会将支付结果通过异步回调的方式请求 支付通知接口 进行通知。本路由可以修改相关 Setting 配置,或在模块启动时使用 Configure<AbpWeChatPayOptions>()
方法,对 NotifyUrl
参数进行配置,您可参考上文“模块的配置”章节了解如何修改配置。
用户如果需要对支付结果进行处理,只需要实现一个或多个 IWeChatPayEventHandler
处理器即可。当框架接受到微信通知时,会触发开发人员编写的处理器,并将微信结果传递给这些处理器。
public class PaidWeChatPayEventHandler : WeChatPayPaidEventHandlerBase
{
public Task<WeChatRequestHandlingResult> HandleAsync(WeChatPayEventModel<WeChatPayPaidEventModel> model)
{
Console.WriteLine("支付成功。");
return Task.FromResult(new WeChatRequestHandlingResult(true));
}
}
编写完成之后,则需要开发人员手动注入这些处理器。
public class XXXDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddTransient<IWeChatPayEventHandler, WeChatPaymentHandler>();
}
}
如果在处理过程当中出现了异常,那么你可以在返回 WeChatRequestHandlingResult
对象时,设置 success
参数为 false
,并且可以填写对应的失败原因。
WeChatPay 模块默认提供了参数校验处理器,各个处理器的调用顺序是按照 注入顺序 来的,目前暂时不支持处理器自定义排序。
退款通知接口的默认路由是 /wechat-pay/refund-notify
。当开发人员发起了退款操作之后,微信会将退款结果通过异步回调的方式请求 退款通知接口 进行通知。本路由可以修改相关 Setting 配置,或在模块启动时使用 Configure<AbpWeChatPayOptions>()
方法,对 RefundNotifyUrl
参数进行配置,您可参考上文“模块的配置”章节了解如何修改配置。
用户如果需要对退款通知进行处理,只需要实现一个或多个 IWeChatPayEventHandler
处理器即可。当框架接受到微信通知时,会触发开发人员编写的处理器,并将微信结果传递给这些处理器。
public class RefundWeChatPayEventHandler : WeChatPayRefundEventHandlerBase
{
public Task<WeChatRequestHandlingResult> HandleAsync(WeChatPayEventModel<WeChatPayRefundEventModel> model)
{
Console.WriteLine("退款成功。");
return Task.FromResult(new WeChatRequestHandlingResult(true));
}
}
编写完成之后,则需要开发人员手动注册这些处理器。
public class XXXDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddTransient<IWeChatPayEventHandler, XXXAAAHandler>();
}
}
服务的所有使用方法你都可以参考集成测试项目下的内容 https://github.com/EasyAbp/Abp.WeChat/blob/master/tests/EasyAbp.Abp.WeChat.Pay.Tests/Services。
[Fact]
public async Task CreateOrderAsync_Test()
{
// Arrange
var service = await _weChatPayServiceFactory.CreateAsync<JsPaymentService>();
var request = new CreateOrderRequest
{
MchId = service.MchId,
OutTradeNo = RandomStringHelper.GetRandomString(),
NotifyUrl = AbpWeChatPayTestConsts.NotifyUrl,
AppId = AbpWeChatPayTestConsts.AppId, // 请替换为你的 AppId
Description = "Image形象店-深圳腾大-QQ公仔",
Amount = new CreateOrderAmountModel
{
Total = 1,
Currency = "CNY"
},
Payer = new CreateOrderRequest.CreateOrderPayerModel
{
OpenId = AbpWeChatPayTestConsts.OpenId // 请替换为测试用户的 OpenId,具体 Id 可以在微信公众号平台-用户管理进行查看。
}
};
// Act
var response = await service.CreateOrderAsync(request);
// Assert
response.ShouldNotBeNull();
response.PrepayId.ShouldNotBeNullOrEmpty();
}
[Fact]
public async Task RefundAsync_Test()
{
// Arrange
var service = await _weChatPayServiceFactory.CreateAsync<JsPaymentService>();
var request = new RefundOrderRequest
{
OutRefundNo = RandomStringHelper.GetRandomString(),
OutTradeNo = "kel9xerwcjib2zs8eixyazuis3qsmo",
NotifyUrl = AbpWeChatPayTestConsts.RefundNotifyUrl,
Amount = new RefundOrderRequest.AmountInfo
{
Refund = 1,
Total = 1,
Currency = "CNY"
}
};
// Act
var response = await service.RefundAsync(request);
// Assert
response.ShouldNotBeNull();
response.RefundId.ShouldNotBeNullOrEmpty();
}
在您调用服务,或处理微信请求的事件通知回调时,若提供的 mchId
与 Setting 中的默认值可能不同,则您需要手动实现 IAbpWeChatPayOptionsProvider
,若使用 EasyAbp 封装的支付服务模块,则您无需再手动实现。
本模块提供的用于处理支付结果和退款结果的 HTTP API 回调接口,也支持多商户和多租户,您需要使用这些替代路由:
/wechat-pay/notify
/wechat-pay/notify/tenant-id/{tenantId}
/wechat-pay/notify/mch-id/{mchId}
/wechat-pay/notify/tenant-id/{tenantId}/mch-id/{mchId}
/wechat-pay/refund-notify
/wechat-pay/refund-notify/tenant-id/{tenantId}
/wechat-pay/refund-notify/mch-id/{mchId}
/wechat-pay/refund-notify/tenant-id/{tenantId}/mch-id/{mchId}