// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 // // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 // // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! using Furion.Logging.Extensions; using Newtonsoft.Json; namespace Admin.NET.Core.Service; /// /// 微信支付服务 🧩 /// [ApiDescriptionSettings(Order = 210, Description = "微信支付")] public class SysWechatPayService : IDynamicApiController, ITransient { private static readonly List wechatPayEventHandlers = new List(); /// /// 注册支付记录变化事件处理器 /// /// 处理器 /// 排序,数据越大越先执行 public static void AddPayEventInterceptor(WechatPayEventInterceptor eh, int order) { eh.Order = order; wechatPayEventHandlers.Add(eh); wechatPayEventHandlers.Sort((a, b) => b.Order - a.Order); } private readonly SqlSugarRepository _sysWechatPayRep; private readonly SqlSugarRepository _sysWechatRefundRep; private readonly WechatPayOptions _wechatPayOptions; private readonly PayCallBackOptions _payCallBackOptions; private readonly WechatTenpayClient _wechatTenpayClient; public SysWechatPayService(SqlSugarRepository sysWechatPayRep, SqlSugarRepository sysWechatRefundRep, IOptions wechatPayOptions, IOptions payCallBackOptions) { _sysWechatPayRep = sysWechatPayRep; _sysWechatRefundRep = sysWechatRefundRep; _wechatPayOptions = wechatPayOptions.Value; _payCallBackOptions = payCallBackOptions.Value; _wechatTenpayClient = CreateTenpayClient(); } /// /// 初始化微信支付客户端 /// /// private WechatTenpayClient CreateTenpayClient() { var cerFilePath = App.WebHostEnvironment.ContentRootPath + _wechatPayOptions.MerchantCertificatePrivateKey; if (!File.Exists(cerFilePath)) Log.Warning("商户证书文件不存在:" + cerFilePath); var tenpayClientOptions = new WechatTenpayClientOptions() { MerchantId = _wechatPayOptions.MerchantId, MerchantV3Secret = _wechatPayOptions.MerchantV3Secret, MerchantCertificateSerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber, MerchantCertificatePrivateKey = File.Exists(cerFilePath) ? File.ReadAllText(cerFilePath) : "", PlatformCertificateManager = new InMemoryCertificateManager() }; return new WechatTenpayClient(tenpayClientOptions); } /// /// 生成JSAPI调起支付所需参数 🔖 /// /// /// [DisplayName("生成JSAPI调起支付所需参数")] public dynamic GenerateParametersForJsapiPay(WechatPayParaInput input) { return _wechatTenpayClient.GenerateParametersForJsapiPayRequest(_wechatPayOptions.AppId, input.PrepayId); } /// /// 微信支付统一下单获取Id(商户直连) 🔖 /// [DisplayName("微信支付统一下单获取Id(商户直连)")] public async Task CreatePayTransaction([FromBody] WechatPayTransactionInput input) { string outTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000); // 微信需要的订单号(唯一) // 检查订单信息是否已存在(使用“商户交易单号+状态”唯一性判断) var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OrderId == input.OrderId && u.OrderStatus == input.OrderStatus); if (wechatPay != null) { outTradeNumber = wechatPay.OutTradeNumber; } var request = new CreatePayTransactionJsapiRequest() { OutTradeNumber = outTradeNumber, AppId = _wechatPayOptions.AppId, Description = input.Description, Attachment = input.Attachment, GoodsTag = input.GoodsTag, ExpireTime = DateTimeOffset.Now.AddMinutes(10), NotifyUrl = _payCallBackOptions.WechatPayUrl, Amount = new CreatePayTransactionJsapiRequest.Types.Amount() { Total = input.Total }, Payer = new CreatePayTransactionJsapiRequest.Types.Payer() { OpenId = input.OpenId } }; var response = await _wechatTenpayClient.ExecuteCreatePayTransactionJsapiAsync(request); if (!response.IsSuccessful()) throw Oops.Oh(response.ErrorMessage); if (wechatPay == null) { // 保存订单信息 wechatPay = new SysWechatPay() { AppId = _wechatPayOptions.AppId, MerchantId = _wechatPayOptions.MerchantId, OutTradeNumber = request.OutTradeNumber, Description = input.Description, Attachment = input.Attachment, GoodsTag = input.GoodsTag, Total = input.Total, OpenId = input.OpenId, TransactionId = "", OrderId = input.OrderId, OrderStatus = input.OrderStatus, Tags = input.Tags, BusinessId = input.BusinessId, }; await _sysWechatPayRep.InsertAsync(wechatPay); } var singInfo = GenerateParametersForJsapiPay(new WechatPayParaInput() { PrepayId = response.PrepayId }); return new CreatePayTransactionOutput { PrepayId = response.PrepayId, OutTradeNumber = request.OutTradeNumber, SingInfo = singInfo }; } /// /// 微信支付统一下单(商户直连)Native 🔖 /// [DisplayName("微信支付统一下单(商户直连)Native")] public async Task CreatePayTransactionNative([FromBody] WechatPayTransactionInput input) { var request = new CreatePayTransactionNativeRequest() { OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 微信需要的订单号(唯一) AppId = _wechatPayOptions.AppId, Description = input.Description, Attachment = input.Attachment, GoodsTag = input.GoodsTag, ExpireTime = DateTimeOffset.Now.AddMinutes(10), NotifyUrl = _payCallBackOptions.WechatPayUrl, Amount = new CreatePayTransactionNativeRequest.Types.Amount() { Total = input.Total }, //Payer = new CreatePayTransactionNativeRequest.Types.Payer() { OpenId = input.OpenId } Scene = new CreatePayTransactionNativeRequest.Types.Scene() { ClientIp = "127.0.0.1" } }; var response = await _wechatTenpayClient.ExecuteCreatePayTransactionNativeAsync(request); if (!response.IsSuccessful()) { JsonConvert.SerializeObject(response).LogInformation(); throw Oops.Oh(response.ErrorMessage); } // 保存订单信息 var wechatPay = new SysWechatPay() { AppId = _wechatPayOptions.AppId, MerchantId = _wechatPayOptions.MerchantId, OutTradeNumber = request.OutTradeNumber, Description = input.Description, Attachment = input.Attachment, GoodsTag = input.GoodsTag, Total = input.Total, OpenId = input.OpenId, TransactionId = "", QrcodeContent = response.QrcodeUrl, Tags = input.Tags, BusinessId = input.BusinessId, }; await _sysWechatPayRep.InsertAsync(wechatPay); return new CreatePayTransactionNativeOutput { OutTradeNumber = request.OutTradeNumber, QrcodeUrl = response.QrcodeUrl }; } /// /// 微信支付统一下单获取Id(服务商模式) 🔖 /// [DisplayName("微信支付统一下单获取Id(服务商模式)")] public async Task CreatePayPartnerTransaction([FromBody] WechatPayTransactionInput input) { string outTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000); // 微信需要的订单号(唯一) // 检查订单信息是否已存在(使用“商户交易单号+状态”唯一性判断) var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OrderId == input.OrderId && u.OrderStatus == input.OrderStatus); if (wechatPay != null) { outTradeNumber = wechatPay.OutTradeNumber; } var request = new CreatePayPartnerTransactionJsapiRequest() { OutTradeNumber = outTradeNumber, AppId = _wechatPayOptions.AppId, MerchantId = _wechatPayOptions.MerchantId, SubAppId = _wechatPayOptions.AppId, SubMerchantId = _wechatPayOptions.MerchantId, Description = input.Description, Attachment = input.Attachment, GoodsTag = input.GoodsTag, ExpireTime = DateTimeOffset.Now.AddMinutes(10), NotifyUrl = _payCallBackOptions.WechatPayUrl, Amount = new CreatePayPartnerTransactionJsapiRequest.Types.Amount() { Total = input.Total }, Payer = new CreatePayPartnerTransactionJsapiRequest.Types.Payer() { OpenId = input.OpenId } }; var response = await _wechatTenpayClient.ExecuteCreatePayPartnerTransactionJsapiAsync(request); if (!response.IsSuccessful()) throw Oops.Oh($"JSAPI 下单失败(状态码:{response.GetRawStatus()},错误代码:{response.ErrorCode},错误描述:{response.ErrorMessage})"); if (wechatPay == null) { // 保存订单信息 wechatPay = new SysWechatPay() { AppId = _wechatPayOptions.AppId, MerchantId = _wechatPayOptions.MerchantId, SubAppId = _wechatPayOptions.AppId, SubMerchantId = _wechatPayOptions.MerchantId, OutTradeNumber = request.OutTradeNumber, Description = input.Description, Attachment = input.Attachment, GoodsTag = input.GoodsTag, Total = input.Total, OpenId = input.OpenId, TransactionId = "" }; await _sysWechatPayRep.InsertAsync(wechatPay); } return new CreatePayTransactionOutput { PrepayId = response.PrepayId, OutTradeNumber = request.OutTradeNumber }; } /// /// 获取支付订单详情 🔖 /// /// /// [DisplayName("获取支付订单详情")] public async Task GetPayInfo(string tradeId) { return await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == tradeId); } /// /// 获取支付订单详情(微信接口) 🔖 /// /// /// [DisplayName("获取支付订单详情(微信接口)")] public async Task GetPayInfoFromWechat(string tradeId) { var request = new GetPayTransactionByOutTradeNumberRequest(); request.OutTradeNumber = tradeId; var response = await _wechatTenpayClient.ExecuteGetPayTransactionByOutTradeNumberAsync(request); // 修改订单支付状态 var wechatPayOld = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == response.OutTradeNumber && u.MerchantId == response.MerchantId); SysWechatPay wechatPayNew = null; if (wechatPayOld != null) wechatPayNew = wechatPayOld.DeepCopy(); // 如果状态不一致就更新数据库中的记录 if (wechatPayNew != null && wechatPayNew.TradeState != response.TradeState) { wechatPayNew.OpenId = response.Payer?.OpenId; wechatPayNew.TransactionId = response.TransactionId; // 支付订单号 wechatPayNew.TradeType = response.TradeType; // 交易类型 wechatPayNew.TradeState = response.TradeState; // 交易状态 wechatPayNew.TradeStateDescription = response.TradeStateDescription; // 交易状态描述 wechatPayNew.BankType = response.BankType; // 付款银行类型 if (response.Amount != null) { wechatPayNew.Total = response.Amount.Total; // 订单总金额 wechatPayNew.PayerTotal = response.Amount.PayerTotal; // 用户支付金额 } if (response.SuccessTime.HasValue) wechatPayNew.SuccessTime = response.SuccessTime.Value.DateTime; // 支付完成时间 else wechatPayNew.SuccessTime = DateTime.Now; await _sysWechatPayRep.AsUpdateable(wechatPayNew).IgnoreColumns(true).ExecuteCommandAsync(); } if (wechatPayOld == null || wechatPayOld.TradeState != wechatPayNew.TradeState) { // 没必要等所有回调事件处理完再返回给微信,开一个Task执行 _ = Task.Run(async () => { foreach (var eh in wechatPayEventHandlers) { try { //这里一定要用 DeepCopy 来创一个新的对象传进不,不然会被外面的 主线程改变就麻烦了 if (!await eh.PayInforChanged(wechatPayOld, wechatPayNew.DeepCopy())) break; } catch (Exception ex) { $"GetPayInfoFromWechat 中执行微信支付回调{eh.GetType().Name}出错".LogError(ex); } } }); } // 下面这里创建一个新的对象,是因为不想把全部字段都返回 var result = new SysWechatPay() { AppId = _wechatPayOptions.AppId, MerchantId = _wechatPayOptions.MerchantId, SubAppId = _wechatPayOptions.AppId, SubMerchantId = _wechatPayOptions.MerchantId, OutTradeNumber = request.OutTradeNumber, Attachment = response.Attachment, TransactionId = response.TransactionId, TradeType = response.TradeType, // 交易类型 TradeState = response.TradeState, // 交易状态 TradeStateDescription = response.TradeStateDescription, // 交易状态描述 BankType = response.BankType, // 付款银行类型 SuccessTime = response.SuccessTime.HasValue ? response.SuccessTime.Value.DateTime : DateTime.Now // 支付完成时间 }; return result; } /// /// 微信支付成功回调(商户直连) 🔖 /// /// [AllowAnonymous] [DisplayName("微信支付成功回调(商户直连)")] public async Task PayCallBack() { using var ms = new MemoryStream(); await App.HttpContext.Request.Body.CopyToAsync(ms); var b = ms.ToArray(); var callbackJson = Encoding.UTF8.GetString(b); var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson); if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType)) { var callbackResource = _wechatTenpayClient.DecryptEventResource(callbackModel); // 修改订单支付状态 var wechatPayOld = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber && u.MerchantId == callbackResource.MerchantId); if (wechatPayOld == null) return null; var wechatPayNew = wechatPayOld.DeepCopy(); if (callbackResource.Payer != null) wechatPayNew.OpenId = callbackResource.Payer.OpenId; // 支付者标识 wechatPayNew.TransactionId = callbackResource.TransactionId; // 支付订单号 wechatPayNew.TradeType = callbackResource.TradeType; // 交易类型 wechatPayNew.TradeState = callbackResource.TradeState; // 交易状态 wechatPayNew.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述 wechatPayNew.BankType = callbackResource.BankType; // 付款银行类型 wechatPayNew.Total = callbackResource.Amount.Total; // 订单总金额 wechatPayNew.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额 wechatPayNew.SuccessTime = callbackResource.SuccessTime.DateTime; // 支付完成时间 await _sysWechatPayRep.AsUpdateable(wechatPayNew).IgnoreColumns(true).ExecuteCommandAsync(); // 因为这个是回调给微信的,所以这里没必要等所有回调事件处理完再返回给微信,开一个Task执行 if (wechatPayOld.TradeState != wechatPayNew.TradeState) { _ = Task.Run(async () => { foreach (var eh in wechatPayEventHandlers) { try { if (!await eh.PayInforChanged(wechatPayOld, wechatPayNew)) break; } catch (Exception ex) { $"PayCallBack 中执行微信支付回调{eh.GetType().Name}出错".LogError(ex); } } }); } return new WechatPayOutput() { Total = wechatPayNew.Total, Attachment = wechatPayNew.Attachment, GoodsTag = wechatPayNew.GoodsTag, OrderId = long.Parse(wechatPayNew.OrderId) }; } return null; } /// /// 微信退款回调(商户直连) 🔖 /// /// [AllowAnonymous] [DisplayName("微信退款回调(商户直连)")] public async Task RefundCallBack() { using var ms = new MemoryStream(); await App.HttpContext.Request.Body.CopyToAsync(ms); var b = ms.ToArray(); var callbackJson = Encoding.UTF8.GetString(b); var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson); if ("REFUND.SUCCESS".Equals(callbackModel.EventType)) { // 参考:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/refund-result-notice.html try { var callbackRefundResource = _wechatTenpayClient.DecryptEventResource(callbackModel); // 修改订单支付状态 var wechatRefund = await _sysWechatRefundRep.GetFirstAsync(u => u.OutRefundNumber == callbackRefundResource.OutRefundNumber); if (wechatRefund == null) return null; wechatRefund.RefundStatus = callbackRefundResource.RefundStatus; // 交易状态 wechatRefund.SuccessTime = callbackRefundResource.SuccessTime.Value.DateTime; // 支付完成时间 await _sysWechatRefundRep.AsUpdateable(wechatRefund).IgnoreColumns(true).ExecuteCommandAsync(); // 有退款,刷新一下订单状态(通过主动查询Wechat接口获取) // 通过 GetPayInfoFromWechat 也会触发 WechatPayEventHandler,所以这个回调中不用主动调用 await GetPayInfoFromWechat(callbackRefundResource.OutTradeNumber); } catch (Exception ex) { "微信退款回调时出错:".LogError(ex); } } else { callbackModel.EventType.LogInformation(); } return null; } /// /// 微信支付成功回调(服务商模式) 🔖 /// /// [AllowAnonymous] [DisplayName("微信支付成功回调(服务商模式)")] public async Task PayPartnerCallBack() { using var ms = new MemoryStream(); await App.HttpContext.Request.Body.CopyToAsync(ms); var b = ms.ToArray(); var callbackJson = Encoding.UTF8.GetString(b); var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson); if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType)) { var callbackResource = _wechatTenpayClient.DecryptEventResource(callbackModel); // 修改订单支付状态 var wechatPayOld = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber && u.MerchantId == callbackResource.MerchantId); if (wechatPayOld == null) return; var wechatPayNew = wechatPayOld.DeepCopy(); //wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识 //wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号 //wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号 wechatPayNew.TransactionId = callbackResource.TransactionId; // 支付订单号 wechatPayNew.TradeType = callbackResource.TradeType; // 交易类型 wechatPayNew.TradeState = callbackResource.TradeState; // 交易状态 wechatPayNew.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述 wechatPayNew.BankType = callbackResource.BankType; // 付款银行类型 wechatPayNew.Total = callbackResource.Amount.Total; // 订单总金额 wechatPayNew.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额 wechatPayNew.SuccessTime = callbackResource.SuccessTime.DateTime; // 支付完成时间 await _sysWechatPayRep.AsUpdateable(wechatPayNew).IgnoreColumns(true).ExecuteCommandAsync(); // 因为这个是回调给微信的,所以这里没必要等所有回调事件处理完再返回给微信,开一个Task执行 if (wechatPayOld.TradeState != wechatPayNew.TradeState) { _ = Task.Run(async () => { foreach (var eh in wechatPayEventHandlers) { try { if (!await eh.PayInforChanged(wechatPayOld, wechatPayNew)) break; } catch (Exception ex) { $"PayPartnerCallBack 中执行微信支付回调{eh.GetType().Name}出错".LogError(ex); } } }); } } } /// /// 退款申请 🔖 /// https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/create.html /// /// /// [DisplayName("微信退款申请)")] public async Task Refund(RefundRequestInput input) { var vechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == input.OutTradeNumber); if (vechatPay == null) { throw Oops.Bah("没有相应支付记录"); } var request = new CreateRefundDomesticRefundRequest() { OutTradeNumber = input.OutTradeNumber, OutRefundNumber = "REFUND_" + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff"), NotifyUrl = _payCallBackOptions.WechatRefundUrl, Amount = new CreateRefundDomesticRefundRequest.Types.Amount() { Total = input.Total, Refund = input.Refund }, Reason = input.Reason, }; var response = await _wechatTenpayClient.ExecuteCreateRefundDomesticRefundAsync(request); if (!response.IsSuccessful()) { // 退款失败,该单可能已经退款了,所以主动查询微信接口更新状态 try { await this.GetPayInfoFromWechat(input.OutTradeNumber); } catch { } throw Oops.Oh($"JSAPI 退款申请失败(状态码:{response.GetRawStatus()},错误代码:{response.ErrorCode},错误描述:{response.ErrorMessage})"); } var wechatRefund = await _sysWechatRefundRep.GetFirstAsync(u => u.OutTradeNumber == input.OutTradeNumber); if (wechatRefund == null) { // 保存退款申请信息 wechatRefund = new SysWechatRefund() { TransactionId = vechatPay.TransactionId, OutTradeNumber = input.OutTradeNumber, OutRefundNumber = request.OutRefundNumber, // 每笔付款只退一次,所以这里直接用付款单号 Reason = request.Reason, Refund = input.Refund, RefundId = response.RefundId, Total = input.Total, NotifyUrl = _payCallBackOptions.WechatRefundUrl, OrderId = input.OrderId, RefundStatus = input.OrderStatus, MerchantGoodsId = input.MerchantGoodsId, GoodsName = input.GoodsName, UnitPrice = input.UnitPrice, RefundAmount = input.RefundAmount, RefundQuantity = input.RefundQuantity, Attachment = input.Attachment, Remark = input.Remark }; await _sysWechatRefundRep.InsertAsync(wechatRefund); // 发送了退款请求也要更新原定单的状态(从微信查询) await this.GetPayInfoFromWechat(input.OutTradeNumber); } } /// /// 查询单笔退款(通过商户退款单号) 🔖 /// https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/query-by-out-refund-no.html /// /// /// [DisplayName("微信查询单笔退款)")] public async Task GetRefundByOutRefundNumber(string outRefundNumber) { var request = new GetRefundDomesticRefundByOutRefundNumberRequest() { OutRefundNumber = outRefundNumber }; return await _wechatTenpayClient.ExecuteGetRefundDomesticRefundByOutRefundNumberAsync(request); } /// /// 微信支付订单号查询(校正) 🔖 /// https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id} /// /// /// [DisplayName("微信支付订单号查询(校正)")] public async Task GetPayTransactionByIdAsync(string transactionId) { if (string.IsNullOrEmpty(transactionId)) throw Oops.Oh("TransactionId 不能为空"); if (string.IsNullOrEmpty(_wechatPayOptions.MerchantId) || string.IsNullOrEmpty(_wechatPayOptions.MerchantCertificateSerialNumber)) throw Oops.Oh("商户号或证书序列号不能为空,请检查支付配置"); var request = new GetPayTransactionByIdRequest() { MerchantId = _wechatPayOptions.MerchantId, TransactionId = transactionId, WechatpaySerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber }; var response = await _wechatTenpayClient.ExecuteGetPayTransactionByIdAsync(request); if (response.TradeState == "SUCCESS" || response.TradeState == "CLOSED" || response.TradeState == "NOTPAY") { // 修正订单支付状态 var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.TransactionId == request.TransactionId && u.MerchantId == request.MerchantId); if (wechatPay != null && string.IsNullOrEmpty(wechatPay.TradeState)) { wechatPay.TradeType = response.TradeType; // 交易类型 wechatPay.TradeState = response.TradeState; // 交易状态 wechatPay.TradeStateDescription = response.TradeStateDescription; // 交易状态描述 wechatPay.OpenId = response.Payer?.OpenId;// 付款用户OpenId wechatPay.BankType = response.BankType; // 付款银行类型 wechatPay.PayerTotal = response.Amount?.PayerTotal; // 用户支付金额 wechatPay.SuccessTime = response.SuccessTime?.DateTime; // 支付完成时间 await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync(); return wechatPay.Adapt(); } } return response.Adapt(); } /// /// 商户订单号查询(校正) 🔖 /// https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no} /// /// /// [DisplayName("微信商户订单号查询(校正)")] public async Task GetPayTransactionByOutTradeNumberAsync(string outTradeNumber) { if (string.IsNullOrEmpty(outTradeNumber)) throw Oops.Oh("商户订单号(OutTradeNumber)不能为空"); if (string.IsNullOrEmpty(_wechatPayOptions.MerchantId) || string.IsNullOrEmpty(_wechatPayOptions.MerchantCertificateSerialNumber)) throw Oops.Oh("商户号或证书序列号不能为空,请检查支付配置"); var request = new GetPayTransactionByOutTradeNumberRequest() { MerchantId = _wechatPayOptions.MerchantId, OutTradeNumber = outTradeNumber, WechatpaySerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber, }; var response = await _wechatTenpayClient.ExecuteGetPayTransactionByOutTradeNumberAsync(request); if (response.TradeState == "SUCCESS" || response.TradeState == "CLOSED" || response.TradeState == "NOTPAY") { // 修正订单支付状态 var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == outTradeNumber && u.MerchantId == request.MerchantId); if (wechatPay != null && string.IsNullOrEmpty(wechatPay.TradeState)) { wechatPay.TransactionId = response.TransactionId; // 支付订单号 wechatPay.TradeType = response.TradeType; // 交易类型 wechatPay.TradeState = response.TradeState; // 交易状态 wechatPay.TradeStateDescription = response.TradeStateDescription; // 交易状态描述 wechatPay.OpenId = response.Payer?.OpenId;// 付款用户OpenId wechatPay.BankType = response.BankType; // 付款银行类型 wechatPay.PayerTotal = response.Amount?.PayerTotal; // 用户支付金额 wechatPay.SuccessTime = response.SuccessTime?.DateTime; // 支付完成时间 await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync(); return wechatPay.Adapt(); } } return response.Adapt(); } /// /// 获取支付记录分页列表 🔖 /// /// PageSysWechatPayInput /// [DisplayName("获取支付记录分页列表")] public async Task> PageAsync(PageSysWechatPayInput input) { var query = _sysWechatPayRep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.OrderId), u => u.OrderId == input.OrderId) .WhereIF(!string.IsNullOrWhiteSpace(input.OrderStatus), u => u.OrderStatus == input.OrderStatus) .WhereIF(!string.IsNullOrWhiteSpace(input.OutTradeNumber), u => u.OutTradeNumber.Contains(input.OutTradeNumber.Trim())); if (input.SuccessTimeRange != null && input.SuccessTimeRange.Count > 0) { DateTime? start = input.SuccessTimeRange[0]; query.WhereIF(start.HasValue, u => u.SuccessTime > start); if (input.SuccessTimeRange.Count > 1 && input.SuccessTimeRange[1].HasValue) { var end = input.SuccessTimeRange[1].Value.AddDays(1); query.Where(u => u.SuccessTime < end); } } if (input.ExpireTimeRange != null && input.ExpireTimeRange.Count > 0) { DateTime? start = input.ExpireTimeRange[0]; query.WhereIF(start.HasValue, u => u.ExpireTime > start); if (input.ExpireTimeRange.Count > 1 && input.ExpireTimeRange[1].HasValue) { var end = input.ExpireTimeRange[1].Value.AddDays(1); query.Where(u => u.ExpireTime < end); } } query.OrderByDescending(u => u.CreateTime); return await query.ToPagedListAsync(input.Page, input.PageSize); } /// /// 根据支付Id获取退款信息列表 🔖 /// /// /// /// [DisplayName("根据支付Id获取退款信息列表")] public async Task> GetRefundList([FromQuery] string transactionId, [FromQuery] string outTradeNumber) { return await _sysWechatRefundRep.AsQueryable() .WhereIF(!string.IsNullOrEmpty(transactionId), u => u.TransactionId == transactionId) .WhereIF(!string.IsNullOrEmpty(outTradeNumber), u => u.OutTradeNumber == outTradeNumber) .ToListAsync(); } }