微信支付–JSAPI支付(微信小程序和微信公众号支付都可以采用该方式)

  • 微信支付–JSAPI支付(微信小程序和微信公众号支付都可以采用该方式)已关闭评论
  • 97 次浏览
  • A+
所属分类:.NET技术
摘要

本实例使用了工具包SKIT.FlurlHttpClient.Wechat.TenpayV3(github:https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat)

本实例使用了工具包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_certapiclient_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_certapiclient_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;         }