536 lines
25 KiB
C#
536 lines
25 KiB
C#
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||
//
|
||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||
//
|
||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||
|
||
using Furion.Logging.Extensions;
|
||
using Newtonsoft.Json;
|
||
|
||
namespace Admin.NET.Core.Service;
|
||
|
||
/// <summary>
|
||
/// 微信支付服务 🧩
|
||
/// </summary>
|
||
[ApiDescriptionSettings(Order = 210, Description = "微信支付")]
|
||
public class SysWechatPayService : IDynamicApiController, ITransient
|
||
{
|
||
private readonly SqlSugarRepository<SysWechatPay> _sysWechatPayRep;
|
||
private readonly SqlSugarRepository<SysWechatRefund> _sysWechatRefundRep;
|
||
private readonly WechatPayOptions _wechatPayOptions;
|
||
private readonly PayCallBackOptions _payCallBackOptions;
|
||
|
||
private readonly WechatTenpayClient _wechatTenpayClient;
|
||
|
||
public SysWechatPayService(SqlSugarRepository<SysWechatPay> sysWechatPayRep,
|
||
SqlSugarRepository<SysWechatRefund> sysWechatRefundRep,
|
||
IOptions<WechatPayOptions> wechatPayOptions,
|
||
IOptions<PayCallBackOptions> payCallBackOptions)
|
||
{
|
||
_sysWechatPayRep = sysWechatPayRep;
|
||
this._sysWechatRefundRep = sysWechatRefundRep;
|
||
_wechatPayOptions = wechatPayOptions.Value;
|
||
_payCallBackOptions = payCallBackOptions.Value;
|
||
|
||
_wechatTenpayClient = CreateTenpayClient();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化微信支付客户端
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成JSAPI调起支付所需参数 🔖
|
||
/// </summary>
|
||
/// <param name="input"></param>
|
||
/// <returns></returns>
|
||
[DisplayName("生成JSAPI调起支付所需参数")]
|
||
public dynamic GenerateParametersForJsapiPay(WechatPayParaInput input)
|
||
{
|
||
return _wechatTenpayClient.GenerateParametersForJsapiPayRequest(_wechatPayOptions.AppId, input.PrepayId);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 微信支付统一下单获取Id(商户直连) 🔖
|
||
/// </summary>
|
||
[DisplayName("微信支付统一下单获取Id(商户直连)")]
|
||
public async Task<CreatePayTransactionOutput> 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<Exception>(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
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 微信支付统一下单(商户直连)Native
|
||
/// </summary>
|
||
[DisplayName("微信支付统一下单(商户直连)Native")]
|
||
public async Task<CreatePayTransactionNativeOutput> 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
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 微信支付统一下单获取Id(服务商模式) 🔖
|
||
/// </summary>
|
||
[DisplayName("微信支付统一下单获取Id(服务商模式)")]
|
||
public async Task<CreatePayTransactionOutput> 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<Exception>($"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
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取支付订单详情 🔖
|
||
/// </summary>
|
||
/// <param name="tradeId"></param>
|
||
/// <returns></returns>
|
||
[DisplayName("获取支付订单详情")]
|
||
public async Task<SysWechatPay> GetPayInfo(string tradeId)
|
||
{
|
||
return await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == tradeId);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 微信支付成功回调(商户直连) 🔖
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[AllowAnonymous]
|
||
[DisplayName("微信支付成功回调(商户直连)")]
|
||
public async Task<WechatPayOutput> 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<TransactionResource>(callbackModel);
|
||
|
||
// 修改订单支付状态
|
||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
||
&& u.MerchantId == callbackResource.MerchantId);
|
||
if (wechatPay == null) return null;
|
||
//wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
|
||
//wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
|
||
//wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
|
||
wechatPay.TransactionId = callbackResource.TransactionId; // 支付订单号
|
||
wechatPay.TradeType = callbackResource.TradeType; // 交易类型
|
||
wechatPay.TradeState = callbackResource.TradeState; // 交易状态
|
||
wechatPay.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
|
||
wechatPay.BankType = callbackResource.BankType; // 付款银行类型
|
||
wechatPay.Total = callbackResource.Amount.Total; // 订单总金额
|
||
wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
|
||
wechatPay.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
|
||
|
||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||
|
||
return new WechatPayOutput()
|
||
{
|
||
Total = wechatPay.Total,
|
||
Attachment = wechatPay.Attachment,
|
||
GoodsTag = wechatPay.GoodsTag
|
||
};
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 微信支付成功回调(服务商模式) 🔖
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[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<PartnerTransactionResource>(callbackModel);
|
||
|
||
// 修改订单支付状态
|
||
var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
|
||
&& u.MerchantId == callbackResource.MerchantId);
|
||
if (wechatPay == null) return;
|
||
//wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
|
||
//wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
|
||
//wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
|
||
wechatPay.TransactionId = callbackResource.TransactionId; // 支付订单号
|
||
wechatPay.TradeType = callbackResource.TradeType; // 交易类型
|
||
wechatPay.TradeState = callbackResource.TradeState; // 交易状态
|
||
wechatPay.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
|
||
wechatPay.BankType = callbackResource.BankType; // 付款银行类型
|
||
wechatPay.Total = callbackResource.Amount.Total; // 订单总金额
|
||
wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
|
||
wechatPay.SuccessTime = callbackResource.SuccessTime; // 支付完成时间
|
||
|
||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 退款申请 🔖
|
||
/// https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/create.html
|
||
/// </summary>
|
||
/// <param name="input"></param>
|
||
/// <returns></returns>
|
||
[DisplayName("微信退款申请)")]
|
||
public async Task Refund(RefundRequestInput input)
|
||
{
|
||
var request = new CreateRefundDomesticRefundRequest()
|
||
{
|
||
OutTradeNumber = input.OutTradeNumber,
|
||
OutRefundNumber = "REFUND_" + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff"),
|
||
Amount = new CreateRefundDomesticRefundRequest.Types.Amount()
|
||
{
|
||
Total = input.Total,
|
||
Refund = input.Refund
|
||
},
|
||
Reason = input.Reason,
|
||
};
|
||
var response = await _wechatTenpayClient.ExecuteCreateRefundDomesticRefundAsync(request);
|
||
|
||
if (!response.IsSuccessful())
|
||
throw Oops.Oh<Exception>($"JSAPI 退款申请失败(状态码:{response.GetRawStatus()},错误代码:{response.ErrorCode},错误描述:{response.ErrorMessage})");
|
||
|
||
var wechatRefund = await _sysWechatRefundRep.GetFirstAsync(u => u.OutTradeNumber == input.OutTradeNumber);
|
||
if (wechatRefund == null)
|
||
{
|
||
// 保存退款申请信息
|
||
wechatRefund = new SysWechatRefund()
|
||
{
|
||
TransactionId = input.OutTradeNumber,
|
||
OutTradeNumber = request.OutTradeNumber,
|
||
OutRefundNo = request.OutTradeNumber, //每笔付款只退一次,所以这里直接用付款单号
|
||
Reason = request.Reason,
|
||
Refund = input.Refund,
|
||
Total = input.Total,
|
||
//NotifyUrl = "",
|
||
OrderId = input.OrderId,
|
||
OrderStatus = 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);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查询单笔退款(通过商户退款单号) 🔖
|
||
/// https://pay.weixin.qq.com/docs/merchant/apis/mini-program-payment/query-by-out-refund-no.html
|
||
/// </summary>
|
||
/// <param name="outRefundNumber"></param>
|
||
/// <returns></returns>
|
||
[DisplayName("微信查询单笔退款)")]
|
||
public async Task<GetRefundDomesticRefundByOutRefundNumberResponse> GetRefundByOutRefundNumber(string outRefundNumber)
|
||
{
|
||
var request = new GetRefundDomesticRefundByOutRefundNumberRequest()
|
||
{
|
||
OutRefundNumber = outRefundNumber
|
||
};
|
||
return await _wechatTenpayClient.ExecuteGetRefundDomesticRefundByOutRefundNumberAsync(request);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 微信支付订单号查询(校正) 🔖
|
||
/// https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id}
|
||
/// </summary>
|
||
/// <param name="transactionId"></param>
|
||
/// <returns></returns>
|
||
[DisplayName("微信支付订单号查询(校正)")]
|
||
public async Task<WechatPayOutput> 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,
|
||
WechatpayCertificateSerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber
|
||
};
|
||
var response = await _wechatTenpayClient.ExecuteGetPayTransactionByIdAsync(request);
|
||
if (response.TradeState == "SUCCESS" || response.TradeState == "CLOSED")
|
||
{
|
||
// 修正订单支付状态
|
||
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.BankType = response.BankType; // 付款银行类型
|
||
wechatPay.PayerTotal = response.Amount?.PayerTotal; // 用户支付金额
|
||
wechatPay.SuccessTime = response.SuccessTime; // 支付完成时间
|
||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||
return wechatPay.Adapt<WechatPayOutput>();
|
||
}
|
||
}
|
||
return response.Adapt<WechatPayOutput>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 商户订单号查询(校正) 🔖
|
||
/// https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}
|
||
/// </summary>
|
||
/// <param name="outTradeNumber"></param>
|
||
/// <returns></returns>
|
||
[DisplayName("微信商户订单号查询(校正)")]
|
||
public async Task<WechatPayOutput> 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,
|
||
WechatpayCertificateSerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber
|
||
};
|
||
var response = await _wechatTenpayClient.ExecuteGetPayTransactionByOutTradeNumberAsync(request);
|
||
if (response.TradeState == "SUCCESS" || response.TradeState == "CLOSED")
|
||
{
|
||
// 修正订单支付状态
|
||
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.BankType = response.BankType; // 付款银行类型
|
||
wechatPay.PayerTotal = response.Amount?.PayerTotal; // 用户支付金额
|
||
wechatPay.SuccessTime = response.SuccessTime; // 支付完成时间
|
||
await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
|
||
return wechatPay.Adapt<WechatPayOutput>();
|
||
}
|
||
}
|
||
return response.Adapt<WechatPayOutput>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取支付记录分页列表 🔖
|
||
/// </summary>
|
||
/// <param name="input">PageSysWechatPayInput</param>
|
||
/// <returns></returns>
|
||
[DisplayName("获取支付记录分页列表")]
|
||
public async Task<SqlSugarPagedList<SysWechatPay>> 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 = 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 = query.Where(u => u.SuccessTime < end);
|
||
}
|
||
}
|
||
if (input.ExpireTimeRange != null && input.ExpireTimeRange.Count > 0)
|
||
{
|
||
DateTime? start = input.ExpireTimeRange[0];
|
||
query = 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 = query.Where(u => u.ExpireTime < end);
|
||
}
|
||
}
|
||
query = query.OrderByDescending(u => u.CreateTime);
|
||
return await query.ToPagedListAsync(input.Page, input.PageSize);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据支付Id获取退款信息列表
|
||
/// </summary>
|
||
/// <param name="transactionId"></param>
|
||
/// <returns></returns>
|
||
[DisplayName("根据支付Id获取退款信息列表")]
|
||
public async Task<List<SysWechatRefund>> GetRefundList([FromQuery] string transactionId)
|
||
{
|
||
return await _sysWechatRefundRep.AsQueryable().Where(u => u.TransactionId == transactionId).ToListAsync();
|
||
}
|
||
} |