SysWechatPayService.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
  2. //
  3. // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
  4. //
  5. // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
  6. using Furion.Logging.Extensions;
  7. using Newtonsoft.Json;
  8. namespace Admin.NET.Core.Service;
  9. /// <summary>
  10. /// 微信支付服务 🧩
  11. /// </summary>
  12. [ApiDescriptionSettings(Order = 210)]
  13. public class SysWechatPayService : IDynamicApiController, ITransient
  14. {
  15. private readonly SqlSugarRepository<SysWechatPay> _sysWechatPayRep;
  16. private readonly SqlSugarRepository<SysWechatRefund> _sysWechatRefundRep;
  17. private readonly WechatPayOptions _wechatPayOptions;
  18. private readonly PayCallBackOptions _payCallBackOptions;
  19. private readonly WechatTenpayClient _wechatTenpayClient;
  20. public SysWechatPayService(SqlSugarRepository<SysWechatPay> sysWechatPayUserRep,
  21. SqlSugarRepository<SysWechatRefund> sysWechatRefundRep,
  22. IOptions<WechatPayOptions> wechatPayOptions,
  23. IOptions<PayCallBackOptions> payCallBackOptions)
  24. {
  25. _sysWechatPayRep = sysWechatPayUserRep;
  26. _sysWechatRefundRep = sysWechatRefundRep;
  27. _wechatPayOptions = wechatPayOptions.Value;
  28. _payCallBackOptions = payCallBackOptions.Value;
  29. _wechatTenpayClient = CreateTenpayClient();
  30. }
  31. /// <summary>
  32. /// 初始化微信支付客户端
  33. /// </summary>
  34. /// <returns></returns>
  35. private WechatTenpayClient CreateTenpayClient()
  36. {
  37. var cerFilePath = App.WebHostEnvironment.ContentRootPath + _wechatPayOptions.MerchantCertificatePrivateKey;
  38. var tenpayClientOptions = new WechatTenpayClientOptions()
  39. {
  40. MerchantId = _wechatPayOptions.MerchantId,
  41. MerchantV3Secret = _wechatPayOptions.MerchantV3Secret,
  42. MerchantCertificateSerialNumber = _wechatPayOptions.MerchantCertificateSerialNumber,
  43. MerchantCertificatePrivateKey = File.Exists(cerFilePath) ? File.ReadAllText(cerFilePath) : "",
  44. PlatformCertificateManager = new InMemoryCertificateManager()
  45. };
  46. return new WechatTenpayClient(tenpayClientOptions);
  47. }
  48. /// <summary>
  49. /// 分页查询支付列表 🔖
  50. /// </summary>
  51. /// <param name="input"></param>
  52. /// <returns></returns>
  53. [HttpPost]
  54. [ApiDescriptionSettings(Name = "Page")]
  55. public async Task<SqlSugarPagedList<SysWechatPay>> Page(WechatPayPageInput input)
  56. {
  57. var query = _sysWechatPayRep.AsQueryable()
  58. .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.OutTradeNumber == input.Keyword || u.TransactionId == input.Keyword)
  59. .WhereIF(input.CreateTimeRange != null && input.CreateTimeRange.Count > 0 && input.CreateTimeRange[0].HasValue, x => x.CreateTime >= input.CreateTimeRange[0])
  60. .WhereIF(input.CreateTimeRange != null && input.CreateTimeRange.Count > 1 && input.CreateTimeRange[1].HasValue, x => x.CreateTime < ((DateTime)input.CreateTimeRange[1]).AddDays(1));
  61. return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
  62. }
  63. /// <summary>
  64. /// 查询退款信息列表
  65. /// </summary>
  66. /// <param name="id"></param>
  67. /// <returns></returns>
  68. [HttpPost]
  69. [DisplayName("根据支付id获取退款信息列表")]
  70. public async Task<List<SysWechatRefund>> ListRefund([FromBody] string id)
  71. {
  72. var query = _sysWechatRefundRep.AsQueryable()
  73. .Where(u => u.TransactionId == id);
  74. return await query.ToListAsync();
  75. }
  76. /// <summary>
  77. /// 生成JSAPI调起支付所需参数 🔖
  78. /// </summary>
  79. /// <param name="input"></param>
  80. /// <returns></returns>
  81. [DisplayName("生成JSAPI调起支付所需参数")]
  82. public WechatPayParaOutput GenerateParametersForJsapiPay(WechatPayParaInput input)
  83. {
  84. var data = _wechatTenpayClient.GenerateParametersForJsapiPayRequest(_wechatPayOptions.AppId, input.PrepayId);
  85. return new WechatPayParaOutput()
  86. {
  87. AppId = data["appId"],
  88. TimeStamp = data["timeStamp"],
  89. NonceStr = data["nonceStr"],
  90. Package = data["package"],
  91. SignType = data["signType"],
  92. PaySign = data["paySign"]
  93. };
  94. }
  95. /// <summary>
  96. /// 微信支付下单(商户直连) 🔖
  97. /// </summary>
  98. [DisplayName("微信支付下单(商户直连)")]
  99. public async Task<WechatPayTransactionOutput> CreatePayTransaction([FromBody] WechatPayTransactionInput input)
  100. {
  101. var request = new CreatePayTransactionJsapiRequest()
  102. {
  103. OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 订单号
  104. AppId = _wechatPayOptions.AppId,
  105. Description = input.Description,
  106. Attachment = input.Attachment,
  107. GoodsTag = input.GoodsTag,
  108. ExpireTime = DateTimeOffset.Now.AddMinutes(10),
  109. NotifyUrl = _payCallBackOptions.WechatPayUrl,
  110. Amount = new CreatePayTransactionJsapiRequest.Types.Amount() { Total = input.Total },
  111. Payer = new CreatePayTransactionJsapiRequest.Types.Payer() { OpenId = input.OpenId }
  112. };
  113. var response = await _wechatTenpayClient.ExecuteCreatePayTransactionJsapiAsync(request);
  114. if (!response.IsSuccessful())
  115. throw Oops.Oh(response.ErrorMessage);
  116. var singInfo = this.GenerateParametersForJsapiPay(new WechatPayParaInput() { PrepayId = response.PrepayId });
  117. // 保存订单信息
  118. var wechatPay = new SysWechatPay()
  119. {
  120. AppId = _wechatPayOptions.AppId,
  121. MerchantId = _wechatPayOptions.MerchantId,
  122. OutTradeNumber = request.OutTradeNumber,
  123. Description = input.Description,
  124. Attachment = input.Attachment,
  125. GoodsTag = input.GoodsTag,
  126. Total = input.Total,
  127. OpenId = input.OpenId,
  128. TransactionId = "",
  129. Tags = input.Tags,
  130. BusinessId = input.BusinessId,
  131. };
  132. await _sysWechatPayRep.InsertAsync(wechatPay);
  133. return new WechatPayTransactionOutput()
  134. {
  135. PrepayId = response.PrepayId,
  136. OutTradeNumber = request.OutTradeNumber,
  137. SingInfo = singInfo
  138. };
  139. }
  140. /// <summary>
  141. /// 微信支付下单(商户直连)Native
  142. /// </summary>
  143. [DisplayName("微信支付下单(商户直连)Native")]
  144. public async Task<dynamic> CreatePayTransactionNative([FromBody] WechatPayTransactionInput input)
  145. {
  146. var request = new CreatePayTransactionNativeRequest()
  147. {
  148. OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 订单号
  149. AppId = _wechatPayOptions.AppId,
  150. Description = input.Description,
  151. Attachment = input.Attachment,
  152. GoodsTag = input.GoodsTag,
  153. ExpireTime = DateTimeOffset.Now.AddMinutes(10),
  154. NotifyUrl = _payCallBackOptions.WechatPayUrl,
  155. Amount = new CreatePayTransactionNativeRequest.Types.Amount() { Total = input.Total },
  156. //Payer = new CreatePayTransactionNativeRequest.Types.Payer() { OpenId = input.OpenId }
  157. Scene = new CreatePayTransactionNativeRequest.Types.Scene() { ClientIp = "127.0.0.1" }
  158. };
  159. var response = await _wechatTenpayClient.ExecuteCreatePayTransactionNativeAsync(request);
  160. if (!response.IsSuccessful())
  161. {
  162. JsonConvert.SerializeObject(response).LogInformation();
  163. throw Oops.Oh(response.ErrorMessage);
  164. }
  165. // 保存订单信息
  166. var wechatPay = new SysWechatPay()
  167. {
  168. AppId = _wechatPayOptions.AppId,
  169. MerchantId = _wechatPayOptions.MerchantId,
  170. OutTradeNumber = request.OutTradeNumber,
  171. Description = input.Description,
  172. Attachment = input.Attachment,
  173. GoodsTag = input.GoodsTag,
  174. Total = input.Total,
  175. //OpenId = input.OpenId,
  176. TransactionId = "",
  177. QrcodeContent = response.QrcodeUrl,
  178. Tags = input.Tags,
  179. BusinessId = input.BusinessId,
  180. };
  181. await _sysWechatPayRep.InsertAsync(wechatPay);
  182. return new
  183. {
  184. request.OutTradeNumber,
  185. response.QrcodeUrl
  186. };
  187. }
  188. /// <summary>
  189. /// 微信支付下单(服务商模式) 🔖
  190. /// </summary>
  191. [DisplayName("微信支付下单(服务商模式)")]
  192. public async Task<dynamic> CreatePayPartnerTransaction([FromBody] WechatPayTransactionInput input)
  193. {
  194. var request = new CreatePayPartnerTransactionJsapiRequest()
  195. {
  196. OutTradeNumber = DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 订单号
  197. AppId = _wechatPayOptions.AppId,
  198. MerchantId = _wechatPayOptions.MerchantId,
  199. SubAppId = _wechatPayOptions.AppId,
  200. SubMerchantId = _wechatPayOptions.MerchantId,
  201. Description = input.Description,
  202. Attachment = input.Attachment,
  203. GoodsTag = input.GoodsTag,
  204. ExpireTime = DateTimeOffset.Now.AddMinutes(10),
  205. NotifyUrl = _payCallBackOptions.WechatPayUrl,
  206. Amount = new CreatePayPartnerTransactionJsapiRequest.Types.Amount() { Total = input.Total },
  207. Payer = new CreatePayPartnerTransactionJsapiRequest.Types.Payer() { OpenId = input.OpenId }
  208. };
  209. var response = await _wechatTenpayClient.ExecuteCreatePayPartnerTransactionJsapiAsync(request);
  210. if (!response.IsSuccessful())
  211. throw Oops.Oh(response.ErrorMessage);
  212. var singInfo = this.GenerateParametersForJsapiPay(new WechatPayParaInput() { PrepayId = response.PrepayId });
  213. // 保存订单信息
  214. var wechatPay = new SysWechatPay()
  215. {
  216. AppId = _wechatPayOptions.AppId,
  217. MerchantId = _wechatPayOptions.MerchantId,
  218. SubAppId = _wechatPayOptions.AppId,
  219. SubMerchantId = _wechatPayOptions.MerchantId,
  220. OutTradeNumber = request.OutTradeNumber,
  221. Description = input.Description,
  222. Attachment = input.Attachment,
  223. GoodsTag = input.GoodsTag,
  224. Total = input.Total,
  225. OpenId = input.OpenId,
  226. TransactionId = ""
  227. };
  228. await _sysWechatPayRep.InsertAsync(wechatPay);
  229. return new
  230. {
  231. response.PrepayId,
  232. request.OutTradeNumber,
  233. singInfo
  234. };
  235. }
  236. /// <summary>
  237. /// 获取支付订单详情(本地库) 🔖
  238. /// </summary>
  239. /// <param name="tradeId"></param>
  240. /// <returns></returns>
  241. [DisplayName("获取支付订单详情(本地库)")]
  242. public async Task<SysWechatPay> GetPayInfo(string tradeId)
  243. {
  244. return await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == tradeId);
  245. }
  246. /// <summary>
  247. /// 获取支付订单详情(微信接口) 🔖
  248. /// </summary>
  249. /// <param name="tradeId"></param>
  250. /// <returns></returns>
  251. [DisplayName("获取支付订单详情(微信接口)")]
  252. public async Task<SysWechatPay> GetPayInfoFromWechat(string tradeId)
  253. {
  254. var request = new GetPayTransactionByOutTradeNumberRequest();
  255. request.OutTradeNumber = tradeId;
  256. var response = await _wechatTenpayClient.ExecuteGetPayTransactionByOutTradeNumberAsync(request);
  257. // 修改订单支付状态
  258. var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == response.OutTradeNumber
  259. && u.MerchantId == response.MerchantId);
  260. // 如果状态不一致就更新数据库中的记录
  261. if (wechatPay != null && wechatPay.TradeState != response.TradeState)
  262. {
  263. wechatPay.OpenId = response.Payer.OpenId;
  264. wechatPay.TransactionId = response.TransactionId; // 支付订单号
  265. wechatPay.TradeType = response.TradeType; // 交易类型
  266. wechatPay.TradeState = response.TradeState; // 交易状态
  267. wechatPay.TradeStateDescription = response.TradeStateDescription; // 交易状态描述
  268. wechatPay.BankType = response.BankType; // 付款银行类型
  269. wechatPay.Total = response.Amount.Total; // 订单总金额
  270. wechatPay.PayerTotal = response.Amount.PayerTotal; // 用户支付金额
  271. wechatPay.SuccessTime = response.SuccessTime.Value.DateTime; // 支付完成时间
  272. await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
  273. }
  274. wechatPay = new SysWechatPay()
  275. {
  276. AppId = _wechatPayOptions.AppId,
  277. MerchantId = _wechatPayOptions.MerchantId,
  278. SubAppId = _wechatPayOptions.AppId,
  279. SubMerchantId = _wechatPayOptions.MerchantId,
  280. OutTradeNumber = request.OutTradeNumber,
  281. Attachment = response.Attachment,
  282. Total = response.Amount.Total, // 订单总金额
  283. TransactionId = response.TransactionId,
  284. TradeType = response.TradeType, // 交易类型
  285. TradeState = response.TradeState, // 交易状态
  286. TradeStateDescription = response.TradeStateDescription, // 交易状态描述
  287. BankType = response.BankType, // 付款银行类型
  288. PayerTotal = response.Amount.PayerTotal, // 用户支付金额
  289. SuccessTime = response.SuccessTime.Value.DateTime // 支付完成时间
  290. };
  291. return wechatPay;
  292. }
  293. /// <summary>
  294. /// 退款申请
  295. /// </summary>
  296. /// <param name="input"></param>
  297. /// <returns></returns>
  298. [DisplayName("退款申请")]
  299. [HttpPost]
  300. public async Task<dynamic> CreateRefundDomestic([FromBody] WechatPayRefundDomesticInput input)
  301. {
  302. // refund/domestic/refunds
  303. var request = new CreateRefundDomesticRefundRequest()
  304. {
  305. Amount = new CreateRefundDomesticRefundRequest.Types.Amount()
  306. {
  307. Refund = input.Refund,
  308. Total = input.Total,
  309. Currency = "CNY"
  310. },
  311. OutTradeNumber = input.TradeId,
  312. OutRefundNumber = "R" + DateTimeOffset.Now.ToString("yyyyMMddHHmmssfff") + (new Random()).Next(100, 1000), // 订单号
  313. NotifyUrl = _payCallBackOptions.WechatRefundUrl, // 应采用WechatRefundUrl参数,如与WechatPayUrl入口相同,也应分开设置参数
  314. Reason = input.Reason,
  315. };
  316. var response = await _wechatTenpayClient.ExecuteCreateRefundDomesticRefundAsync(request);
  317. if (string.IsNullOrEmpty(response.ErrorCode))
  318. {
  319. // 成功了,这里应该保存退款订单信息
  320. var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == response.OutTradeNumber);
  321. // 保存订单信息
  322. if (wechatPay != null)
  323. {
  324. var wechatRefund = new SysWechatRefund()
  325. {
  326. WechatPayId = wechatPay.Id,
  327. TransactionId = response.TransactionId,
  328. Refund = input.Refund,
  329. Reason = input.Reason,
  330. OutRefundNumber = request.OutRefundNumber,
  331. Channel = response.Channel,
  332. UserReceivedAccount = response.UserReceivedAccount,
  333. };
  334. await _sysWechatRefundRep.InsertAsync(wechatRefund);
  335. }
  336. }
  337. else
  338. {
  339. throw Oops.Bah($"[{response.ErrorCode}]{response.ErrorMessage}");
  340. }
  341. return response;
  342. }
  343. /// <summary>
  344. /// 获取退款订单详情(微信接口)
  345. /// </summary>
  346. /// <param name="refundId"></param>
  347. /// <returns></returns>
  348. [DisplayName("获取退款订单详情(微信接口)")]
  349. public async Task<SysWechatRefund> GetRefundInfoFromWechat(string refundId)
  350. {
  351. var request = new GetRefundDomesticRefundByOutRefundNumberRequest();
  352. request.OutRefundNumber = refundId;
  353. var response = await _wechatTenpayClient.ExecuteGetRefundDomesticRefundByOutRefundNumberAsync(request);
  354. // 修改订单支付状态
  355. var wechatRefund = await _sysWechatRefundRep.GetFirstAsync(u => u.OutRefundNumber == refundId);
  356. // 如果状态不一致就更新数据库中的记录
  357. if (wechatRefund != null && wechatRefund.TradeState != response.Status)
  358. {
  359. wechatRefund.TransactionId = response.TransactionId; // 支付订单号
  360. wechatRefund.TradeState = response.Status; // 交易状态
  361. wechatRefund.SuccessTime = response.SuccessTime.Value.DateTime; // 支付完成时间
  362. await _sysWechatRefundRep.AsUpdateable(wechatRefund).IgnoreColumns(true).ExecuteCommandAsync();
  363. // 有退款,刷新一下订单状态
  364. var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.Id == wechatRefund.WechatPayId);
  365. if (wechatPay != null)
  366. await GetPayInfoFromWechat(wechatPay.OutTradeNumber);
  367. }
  368. wechatRefund = new SysWechatRefund()
  369. {
  370. TransactionId = response.TransactionId,
  371. Refund = response.Amount.Refund,
  372. OutRefundNumber = request.OutRefundNumber,
  373. Channel = response.Channel,
  374. UserReceivedAccount = response.UserReceivedAccount,
  375. TradeState = response.Status, // 交易状态
  376. SuccessTime = response.SuccessTime.Value.DateTime, // 支付完成时间
  377. };
  378. return wechatRefund;
  379. }
  380. /// <summary>
  381. /// 微信支付成功回调(商户直连)
  382. /// </summary>
  383. /// <returns></returns>
  384. [AllowAnonymous]
  385. [DisplayName("微信支付成功回调(商户直连)")]
  386. public async Task<WechatPayOutput> PayCallBack()
  387. {
  388. using var ms = new MemoryStream();
  389. await App.HttpContext.Request.Body.CopyToAsync(ms);
  390. var b = ms.ToArray();
  391. var callbackJson = Encoding.UTF8.GetString(b);
  392. var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson);
  393. if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
  394. {
  395. try
  396. {
  397. var callbackPayResource = _wechatTenpayClient.DecryptEventResource<TransactionResource>(callbackModel);
  398. // 修改订单支付状态
  399. var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackPayResource.OutTradeNumber
  400. && u.MerchantId == callbackPayResource.MerchantId);
  401. if (wechatPay == null) return null;
  402. wechatPay.OpenId = callbackPayResource.Payer.OpenId; // 支付者标识
  403. //wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
  404. //wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
  405. wechatPay.TransactionId = callbackPayResource.TransactionId; // 支付订单号
  406. wechatPay.TradeType = callbackPayResource.TradeType; // 交易类型
  407. wechatPay.TradeState = callbackPayResource.TradeState; // 交易状态
  408. wechatPay.TradeStateDescription = callbackPayResource.TradeStateDescription; // 交易状态描述
  409. wechatPay.BankType = callbackPayResource.BankType; // 付款银行类型
  410. wechatPay.Total = callbackPayResource.Amount.Total; // 订单总金额
  411. wechatPay.PayerTotal = callbackPayResource.Amount.PayerTotal; // 用户支付金额
  412. wechatPay.SuccessTime = callbackPayResource.SuccessTime.DateTime; // 支付完成时间
  413. await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
  414. return new WechatPayOutput()
  415. {
  416. Total = wechatPay.Total,
  417. Attachment = wechatPay.Attachment,
  418. GoodsTag = wechatPay.GoodsTag
  419. };
  420. }
  421. catch (Exception ex)
  422. {
  423. "微信支付回调时出错:".LogError(ex);
  424. }
  425. }
  426. else if ("REFUND.SUCCESS".Equals(callbackModel.EventType))
  427. {
  428. //参考:https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/refund-result-notice.html
  429. try
  430. {
  431. var callbackRefundResource = _wechatTenpayClient.DecryptEventResource<RefundResource>(callbackModel);
  432. // 修改订单支付状态
  433. var wechatRefund = await _sysWechatRefundRep.GetFirstAsync(u => u.OutRefundNumber == callbackRefundResource.OutRefundNumber);
  434. if (wechatRefund == null) return null;
  435. wechatRefund.TradeState = callbackRefundResource.RefundStatus; // 交易状态
  436. wechatRefund.SuccessTime = callbackRefundResource.SuccessTime.Value.DateTime; // 支付完成时间
  437. await _sysWechatRefundRep.AsUpdateable(wechatRefund).IgnoreColumns(true).ExecuteCommandAsync();
  438. // 有退款,刷新一下订单状态
  439. await GetPayInfoFromWechat(callbackRefundResource.OutTradeNumber);
  440. }
  441. catch (Exception ex)
  442. {
  443. "微信退款回调时出错:".LogError(ex);
  444. }
  445. }
  446. else
  447. {
  448. callbackModel.EventType.LogInformation();
  449. }
  450. return null;
  451. }
  452. /// <summary>
  453. /// 微信支付成功回调(服务商模式) 🔖
  454. /// </summary>
  455. /// <returns></returns>
  456. [AllowAnonymous]
  457. [DisplayName("微信支付成功回调(服务商模式)")]
  458. public async Task PayPartnerCallBack()
  459. {
  460. using var ms = new MemoryStream();
  461. await App.HttpContext.Request.Body.CopyToAsync(ms);
  462. var b = ms.ToArray();
  463. var callbackJson = Encoding.UTF8.GetString(b);
  464. var callbackModel = _wechatTenpayClient.DeserializeEvent(callbackJson);
  465. if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
  466. {
  467. var callbackResource = _wechatTenpayClient.DecryptEventResource<PartnerTransactionResource>(callbackModel);
  468. // 修改订单支付状态
  469. var wechatPay = await _sysWechatPayRep.GetFirstAsync(u => u.OutTradeNumber == callbackResource.OutTradeNumber
  470. && u.MerchantId == callbackResource.MerchantId);
  471. if (wechatPay == null) return;
  472. //wechatPay.OpenId = callbackResource.Payer.OpenId; // 支付者标识
  473. //wechatPay.MerchantId = callbackResource.MerchantId; // 微信商户号
  474. //wechatPay.OutTradeNumber = callbackResource.OutTradeNumber; // 商户订单号
  475. wechatPay.TransactionId = callbackResource.TransactionId; // 支付订单号
  476. wechatPay.TradeType = callbackResource.TradeType; // 交易类型
  477. wechatPay.TradeState = callbackResource.TradeState; // 交易状态
  478. wechatPay.TradeStateDescription = callbackResource.TradeStateDescription; // 交易状态描述
  479. wechatPay.BankType = callbackResource.BankType; // 付款银行类型
  480. wechatPay.Total = callbackResource.Amount.Total; // 订单总金额
  481. wechatPay.PayerTotal = callbackResource.Amount.PayerTotal; // 用户支付金额
  482. wechatPay.SuccessTime = callbackResource.SuccessTime.DateTime; // 支付完成时间
  483. await _sysWechatPayRep.AsUpdateable(wechatPay).IgnoreColumns(true).ExecuteCommandAsync();
  484. }
  485. }
  486. }