本實例使用了工具包SKIT.FlurlHttpClient.Wechat.TenpayV3(github:https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat) 示例中的_repositoryWrapper的相關使用是我們 ...
本實例使用了工具包SKIT.FlurlHttpClient.Wechat.TenpayV3(github:https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat)
示例中的_repositoryWrapper的相關使用是我們業務中的業務代碼,使用者可以根據自己的業務自行刪除。
1、生成預支付訂單(供前端調用,返回的信息供小程式端或公眾號端調起微信支付).
public async Task<PayTransactionDto> GeneratePrePaidOrder(PrePaidOrderRequestDto orderBasic) { string orderStatus = await _repositoryWrapper.OrderRepository.QueryOrderStatusAsync(orderBasic.OrderId); //訂單已取消||訂單已支付 if (orderStatus == OrderStatus.Cancel.ToString("D") || orderStatus == OrderStatus.PaySuccess.ToString("D")) { PayTransactionDto payTransaction = new() { OrderStatus = orderStatus, }; return payTransaction; } //string serialNumber = RSAUtility.ExportSerialNumber(@"D:\1630126864_20220905_cert\apiclient_cert.pem"); var manager = new InMemoryCertificateManager(); var options = new WechatTenpayClientOptions() { MerchantId = _config["MerchantId"],//商戶號 MerchantV3Secret = _config["MerchantV3Secret"],//商戶API v3密鑰 MerchantCertificateSerialNumber = _config["MerchantCertificateSerialNumber"],//商戶API證書序列號 MerchantCertificatePrivateKey = FileContentHelper.ReadFileContent("apiclient_key.pem", Path.Combine(AppContext.BaseDirectory, "apiclient_key.pem")),//商戶API證書私鑰 PlatformCertificateManager = manager // 證書管理器的具體用法請參閱下文的高級技巧與加密、驗簽有關的章節 }; var client = new WechatTenpayClient(options); /* 以 JSAPI 統一下單介面為例 */ //var userLogin = await _userService.UserLogin(orderBasic.JSCode); Log.Information("OpenId is " + orderBasic.OpenId); Log.Information("OrderId is " + orderBasic.OrderId); IEnumerable<OrderDetailEntity> orderList = await _repositoryWrapper.OrderRepository.GetOrderPriceAndQty(orderBasic.OrderId); int total = 0; foreach (OrderDetailEntity orderDetail in orderList) { total += orderDetail.TicketTypePrice * 100 * orderDetail.Qty; } total = (int)(total - orderBasic.UseWalletAmount * 100); long orderNumber = await _repositoryWrapper.OrderRepository.QueryOrderNumberByOrderIdAsync(orderBasic.OrderId); var request = new CreatePayTransactionJsapiRequest() { OutTradeNumber = orderNumber.ToString(), AppId = _config["EmscnplAppId"],//微信 AppId Description = $"訂單號為{orderNumber}", ExpireTime = DateTimeOffset.Now.AddSeconds(200), NotifyUrl = _config["wechatPayNotifyUrl"],//回調地址 Amount = new() { Total = total //Total = 1 }, Payer = new() { OpenId = orderBasic.OpenId //OpenId = "oLS5G5C9C2KZuYo-Y9HhyyP-RiFs" }, Attachment = orderBasic.UseWalletAmount.ToString(), }; //var response = await client.ExecuteCreatePayTransactionH5Async(request); var response = await client.ExecuteCreatePayTransactionJsapiAsync(request); Log.Information("response ExecuteCreatePayTransactionJsapiAsync {@response}", response); if (response.IsSuccessful()) { //Console.WriteLine("PrepayId:" + response.PrepayId); //var collection = ExtractQueryParams(response.H5Url); //var prepayId = collection["prepay_id"]; //var package= collection["package"]; var paramMap = client.GenerateParametersForJsapiPayRequest(request.AppId, response.PrepayId); Log.Information("response paramMap {@paramMap}", paramMap); PayTransactionDto payTransaction = new() { WechatpayNonce = paramMap["nonceStr"], WechatpaySignature = paramMap["paySign"], WeChatPrepayId = response.PrepayId, TimeStamp = paramMap["timeStamp"], SignType = paramMap["signType"], Package = paramMap["package"], OrderStatus = orderStatus, }; Log.Information("payTransaction information {@payTransaction}", payTransaction); await _repositoryWrapper.OrderRepository.UpdateOrderStatusAsync(new Contract.OrderStatusDto { OrderId = orderBasic.OrderId, OrderStatus = OrderStatus.PrePay.ToString("D") }); await _repositoryWrapper.RedPackageRepository.BatchUpdateRedPackeStatus(orderBasic.VoucherId, orderBasic.WeChatId, orderBasic.OrderId, RedpackageUseEnum.Lock); await _repositoryWrapper.OrderRepository.BindWechatId(orderBasic.OrderId, orderBasic.WeChatId); return payTransaction; } else { throw new Exception("ExecuteCreatePayTransactionJsapiAsync call return fail"); } }
2、支付完成後的回調方法處理
Controller方法:
/// <summary> /// 支付成功後的回調函數 /// </summary> /// <param name="timestamp"></param> /// <param name="nonce"></param> /// <param name="signature"></param> /// <param name="serialNumber"></param> /// <returns></returns> [HttpPost("WeChatPayNotifyUrl", Name = "WeChatPayNotifyUrl")] public async Task WeChatPayNotifyUrl( [FromHeader(Name = "Wechatpay-Timestamp")] string timestamp, [FromHeader(Name = "Wechatpay-Nonce")] string nonce, [FromHeader(Name = "Wechatpay-Signature")] string signature, [FromHeader(Name = "Wechatpay-Serial")] string serialNumber) { // 接收伺服器推送 // 文檔:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_2.shtml using var reader = new StreamReader(Request.Body, Encoding.UTF8); string content = await reader.ReadToEndAsync(); Log.Information("Wechatpay-Timestamp data is {@content}", content); Log.Information("Wechatpay-Nonce {@nonce}", nonce); Log.Information("Wechatpay-Signature {@signature}", signature); Log.Information("Wechatpay-Serial {@serialNumber}", serialNumber); _weChatAppService.ParseNotifyData(timestamp, nonce, content, signature, serialNumber); }
Service方法:
public async void ParseNotifyData(string timeStamp, string nonce, string content, string signature, string serialNumber) { var manager = new InMemoryCertificateManager(); var options = new WechatTenpayClientOptions() { MerchantId = _config["MerchantId"],//商戶號 MerchantV3Secret = _config["MerchantV3Secret"],//商戶API v3密鑰 MerchantCertificateSerialNumber = _config["MerchantCertificateSerialNumber"],//商戶API證書序列號 MerchantCertificatePrivateKey = FileContentHelper.ReadFileContent("apiclient_key.pem", Path.Combine(AppContext.BaseDirectory, "apiclient_key.pem")),//商戶API證書私鑰 PlatformCertificateManager = manager // 證書管理器的具體用法請參閱下文的高級技巧與加密、驗簽有關的章節 }; var client = new WechatTenpayClient(options); var request = new QueryCertificatesRequest(); var response = await client.ExecuteQueryCertificatesAsync(request); if (response.IsSuccessful()) { response = client.DecryptResponseSensitiveProperty(response); foreach (var certificateModel in response.CertificateList) { manager.AddEntry(new CertificateEntry(certificateModel)); } Log.Information("查詢微信商戶平臺證書成功。"); } bool valid = client.VerifyEventSignature(timeStamp, nonce, content, signature, serialNumber, out Exception? error); if (valid) { /* 將 JSON 反序列化得到通知對象 */ /* 你也可以將 WechatTenpayEvent 類型直接綁定到 MVC 模型上,這樣就不再需要手動反序列化 */ var callbackModel = client.DeserializeEvent(content); if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType)) { /* 根據事件類型,解密得到支付通知敏感數據 */ var callbackResource = client.DecryptEventResource<TransactionResource>(callbackModel); string outTradeNumber = callbackResource.OutTradeNumber; string transactionId = callbackResource.TransactionId; Log.Information("回調返回的解密數據為{@callbackResource}", callbackResource); Console.WriteLine("訂單 {0} 已完成支付,交易單號為 {1}", outTradeNumber, transactionId); Log.Information("outTradeNumber is " + outTradeNumber); Log.Information("outTradeNumber is " + transactionId); #region[存取支付結果] string boxCode = await GetBoxCodeByOrderNumber(Convert.ToInt64(outTradeNumber)); //解綁機器; await _repositoryWrapper.UserBoxRepository.UnBindBox(boxCode); var orderId = await _repositoryWrapper.OrderRepository.QueryOrderIdByOrderNumberAsync(Convert.ToInt64(outTradeNumber)); Log.Information("Update order pay result"); await _repositoryWrapper.OrderRepository.SavePayResult(new OrderEntity() { OrderId = orderId, OutTradeNo = Int64.Parse(outTradeNumber), TradeState = callbackResource.TradeState, TradeStateDesc = callbackResource.TradeStateDescription, BankType = callbackResource.BankType, Total = callbackResource.Amount.Total, OpenId = callbackResource.Payer.OpenId, PayTotal = callbackResource.Amount.PayerTotal, TransactionId = callbackResource.TransactionId, SuccessTime = callbackResource.SuccessTime.ToString() }); #endregion Log.Information("Update order pay status"); if (!String.IsNullOrWhiteSpace(callbackResource.Attachment)) { decimal walletAmount = 0m; if (Decimal.TryParse(callbackResource.Attachment, out walletAmount) && walletAmount > 0) { string weChatId = await _repositoryWrapper.OrderRepository.QueryWeChatIdByOrderId(orderId); await _repositoryWrapper.WalletRepository.PayUseWallet(new List<long>(), orderId, weChatId, walletAmount, false, true); } } await _repositoryWrapper.OrderRepository.UpdateOrderStatusByOrderNumberAsync(Convert.ToInt64(outTradeNumber), OrderStatus.PaySuccess.ToString("D"), (decimal)callbackResource.Amount.PayerTotal / 100); await _repositoryWrapper.RedPackageRepository.BatchUpdateRedPackeStatus(orderId, RedpackageUseEnum.Used); } else { /* 根據事件類型,解密得到支付通知敏感數據 */ var callbackResource = client.DecryptEventResource<TransactionResource>(callbackModel); string outTradeNumber = callbackResource.OutTradeNumber; JObject obj = new(); obj.Add("action", "payFail"); var payFailStr = JsonConvert.SerializeObject(obj); await _repositoryWrapper.OrderRepository.UpdateOrderStatusByOrderNumberAsync(Convert.ToInt64(outTradeNumber), OrderStatus.PayFail.ToString("D"), (decimal)callbackResource.Amount.PayerTotal / 100); } } else { Log.Error("Verify fail"); Log.Error("Verify fail is {@error}", error); } }
3、查詢支付結果
_orderService是我們業務中使用的service,使用方可自行根據自身業務刪除。
public async Task<PayResultDto> QueryOrderPayStatus(OrderBaseDto orderBasic) { PayResultDto payResultDto = new PayResultDto(); string orderStatus = await _repositoryWrapper.OrderRepository.QueryOrderStatusAsync(orderBasic.OrderId); if (orderStatus != null) { OrderStatus orderEnumStatus = OrderStatus.UnDefine; if (System.Enum.TryParse(orderStatus, out orderEnumStatus) && orderEnumStatus == OrderStatus.PaySuccess) { payResultDto.PaySuccess = true; payResultDto.ContributionAmount = await _orderService.GetOrderContributionAsync(orderBasic.OrderId); ; return payResultDto; } } //string serialNumber = RSAUtility.ExportSerialNumber(@"D:\1630126864_20220905_cert\apiclient_cert.pem"); var manager = new InMemoryCertificateManager(); var options = new WechatTenpayClientOptions() { MerchantId = _config["MerchantId"],//商戶號 MerchantV3Secret = _config["MerchantV3Secret"],//商戶API v3密鑰 MerchantCertificateSerialNumber = _config["MerchantCertificateSerialNumber"],//商戶API證書序列號 MerchantCertificatePrivateKey = FileContentHelper.ReadFileContent("apiclient_key.pem", Path.Combine(AppContext.BaseDirectory, "apiclient_key.pem")),//商戶API證書私鑰 PlatformCertificateManager = manager // 證書管理器的具體用法請參閱下文的高級技巧與加密、驗簽有關的章節 }; var client = new WechatTenpayClient(options); /* 以 JSAPI 統一下單介面為例 */ //var userLogin = await _userService.UserLogin(orderBasic.JSCode); Log.Information("OrderId is " + orderBasic.OrderId); long orderNumber = await _repositoryWrapper.OrderRepository.QueryOrderNumberByOrderIdAsync(orderBasic.OrderId); var request = new GetPayTransactionByOutTradeNumberRequest() { OutTradeNumber = orderNumber.ToString(), MerchantId = _config["MerchantId"],//商戶號 WechatpayCertificateSerialNumber = _config["MerchantCertificateSerialNumber"]//商戶API證書序列號 }; var response = await client.ExecuteGetPayTransactionByOutTradeNumberAsync(request); Log.Information("response {@response}", response); if (response.IsSuccessful() && response.TradeState == "SUCCESS") { int payTotal = response.Amount.Total; Console.WriteLine("pay amount:" + payTotal); Log.Information($"QueryOrder order {orderNumber} payTotal is {payTotal}"); if (payTotal > 0) { await _repositoryWrapper.OrderRepository.UpdateOrderStatusAsync(new OrderStatusDto() { OrderId = orderBasic.OrderId, OrderStatus = OrderStatus.PaySuccess.ToString("D"), }); payResultDto.PaySuccess = true; payResultDto.ContributionAmount = await _orderService.GetOrderContributionAsync(orderBasic.OrderId); //payResultDto.Amount = payTotal/100m; } } else { Log.Information($"response.RawStatus is {response.RawStatus}"); Log.Information($"response.ErrorCode is {response.ErrorCode},response.ErrorMessage is {response.ErrorMessage}"); //throw new Exception($"QueryOrder call return fail,orderNumber is {orderNumber}"); } return payResultDto; }
作者:tuohaibei 出處:https://www.cnblogs.com/cby-love 本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須在文章頁面給出原文連接,否則保留追究法律責任的權利. 如果您覺得文章對您有幫助,可以點擊文章右下角"推薦".您的鼓勵是作者堅持原創和持續寫作的最大動力!