翼度科技»论坛 编程开发 .net 查看内容

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

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
本实例使用了工具包SKIT.FlurlHttpClient.Wechat.TenpayV3(github:https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat)
示例中的_repositoryWrapper的相关使用是我们业务中的业务代码,使用者可以根据自己的业务自行删除。
1、生成预支付订单(供前端调用,返回的信息供小程序端或公众号端调起微信支付).
  1. public async Task<PayTransactionDto> GeneratePrePaidOrder(PrePaidOrderRequestDto orderBasic)
  2.         {
  3.             string orderStatus = await _repositoryWrapper.OrderRepository.QueryOrderStatusAsync(orderBasic.OrderId);
  4.             //订单已取消||订单已支付
  5.             if (orderStatus == OrderStatus.Cancel.ToString("D")
  6.                 || orderStatus == OrderStatus.PaySuccess.ToString("D"))
  7.             {
  8.                 PayTransactionDto payTransaction = new()
  9.                 {
  10.                     OrderStatus = orderStatus,
  11.                 };
  12.                 return payTransaction;
  13.             }
  14.             //string serialNumber = RSAUtility.ExportSerialNumber(@"D:\1630126864_20220905_cert\apiclient_cert.pem");
  15.             var manager = new InMemoryCertificateManager();
  16.             var options = new WechatTenpayClientOptions()
  17.             {
  18.                 MerchantId = _config["MerchantId"],//商户号
  19.                 MerchantV3Secret = _config["MerchantV3Secret"],//商户API v3密钥
  20.                 MerchantCertificateSerialNumber = _config["MerchantCertificateSerialNumber"],//商户API证书序列号
  21.                 MerchantCertificatePrivateKey = FileContentHelper.ReadFileContent("apiclient_key.pem", Path.Combine(AppContext.BaseDirectory, "apiclient_key.pem")),//商户API证书私钥
  22.                 PlatformCertificateManager = manager // 证书管理器的具体用法请参阅下文的高级技巧与加密、验签有关的章节
  23.             };
  24.             var client = new WechatTenpayClient(options);
  25.             /* 以 JSAPI 统一下单接口为例 */
  26.             //var userLogin = await _userService.UserLogin(orderBasic.JSCode);
  27.             Log.Information("OpenId is " + orderBasic.OpenId);
  28.             Log.Information("OrderId is " + orderBasic.OrderId);
  29.             IEnumerable<OrderDetailEntity> orderList = await _repositoryWrapper.OrderRepository.GetOrderPriceAndQty(orderBasic.OrderId);
  30.             int total = 0;
  31.             foreach (OrderDetailEntity orderDetail in orderList)
  32.             {
  33.                 total += orderDetail.TicketTypePrice * 100 * orderDetail.Qty;
  34.             }
  35.             total = (int)(total - orderBasic.UseWalletAmount * 100);
  36.             long orderNumber = await _repositoryWrapper.OrderRepository.QueryOrderNumberByOrderIdAsync(orderBasic.OrderId);
  37.             var request = new CreatePayTransactionJsapiRequest()
  38.             {
  39.                 OutTradeNumber = orderNumber.ToString(),
  40.                 AppId = _config["EmscnplAppId"],//微信 AppId
  41.                 Description = $"订单号为{orderNumber}",
  42.                 ExpireTime = DateTimeOffset.Now.AddSeconds(200),
  43.                 NotifyUrl = _config["wechatPayNotifyUrl"],//回调地址
  44.                 Amount = new()
  45.                 {
  46.                     Total = total
  47.                     //Total = 1
  48.                 },
  49.                 Payer = new()
  50.                 {
  51.                     OpenId = orderBasic.OpenId
  52.                     //OpenId = "oLS5G5C9C2KZuYo-Y9HhyyP-RiFs"
  53.                 },
  54.                 Attachment = orderBasic.UseWalletAmount.ToString(),
  55.             };
  56.             //var response = await client.ExecuteCreatePayTransactionH5Async(request);
  57.             var response = await client.ExecuteCreatePayTransactionJsapiAsync(request);
  58.             Log.Information("response ExecuteCreatePayTransactionJsapiAsync {@response}", response);
  59.             if (response.IsSuccessful())
  60.             {
  61.                 //Console.WriteLine("PrepayId:" + response.PrepayId);
  62.                 //var collection = ExtractQueryParams(response.H5Url);
  63.                 //var prepayId = collection["prepay_id"];
  64.                 //var package= collection["package"];
  65.                 var paramMap = client.GenerateParametersForJsapiPayRequest(request.AppId, response.PrepayId);
  66.                 Log.Information("response paramMap {@paramMap}", paramMap);
  67.                 PayTransactionDto payTransaction = new()
  68.                 {
  69.                     WechatpayNonce = paramMap["nonceStr"],
  70.                     WechatpaySignature = paramMap["paySign"],
  71.                     WeChatPrepayId = response.PrepayId,
  72.                     TimeStamp = paramMap["timeStamp"],
  73.                     SignType = paramMap["signType"],
  74.                     Package = paramMap["package"],
  75.                     OrderStatus = orderStatus,
  76.                 };
  77.                 Log.Information("payTransaction information {@payTransaction}", payTransaction);
  78.                 await _repositoryWrapper.OrderRepository.UpdateOrderStatusAsync(new Contract.OrderStatusDto
  79.                 {
  80.                     OrderId = orderBasic.OrderId,
  81.                     OrderStatus = OrderStatus.PrePay.ToString("D")
  82.                 });
  83.                 await _repositoryWrapper.RedPackageRepository.BatchUpdateRedPackeStatus(orderBasic.VoucherId, orderBasic.WeChatId, orderBasic.OrderId, RedpackageUseEnum.Lock);
  84.                 await _repositoryWrapper.OrderRepository.BindWechatId(orderBasic.OrderId, orderBasic.WeChatId);
  85.                 return payTransaction;
  86.             }
  87.             else
  88.             {
  89.                 throw new Exception("ExecuteCreatePayTransactionJsapiAsync call return fail");
  90.             }
  91.         }
复制代码
2、支付完成后的回调方法处理
   Controller方法:
  1. /// <summary>
  2.         /// 支付成功后的回调函数
  3.         /// </summary>
  4.         /// <param name="timestamp"></param>
  5.         /// <param name="nonce"></param>
  6.         /// <param name="signature"></param>
  7.         /// <param name="serialNumber"></param>
  8.         /// <returns></returns>
  9.         [HttpPost("WeChatPayNotifyUrl", Name = "WeChatPayNotifyUrl")]
  10.         public async Task WeChatPayNotifyUrl(
  11.             [FromHeader(Name = "Wechatpay-Timestamp")] string timestamp,
  12.             [FromHeader(Name = "Wechatpay-Nonce")] string nonce,
  13.             [FromHeader(Name = "Wechatpay-Signature")] string signature,
  14.             [FromHeader(Name = "Wechatpay-Serial")] string serialNumber)
  15.         {
  16.             // 接收服务器推送
  17.             // 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_2.shtml
  18.             using var reader = new StreamReader(Request.Body, Encoding.UTF8);
  19.             string content = await reader.ReadToEndAsync();
  20.             Log.Information("Wechatpay-Timestamp data is {@content}", content);
  21.             Log.Information("Wechatpay-Nonce {@nonce}", nonce);
  22.             Log.Information("Wechatpay-Signature {@signature}", signature);
  23.             Log.Information("Wechatpay-Serial {@serialNumber}", serialNumber);
  24.             _weChatAppService.ParseNotifyData(timestamp, nonce, content, signature, serialNumber);
  25.            
  26.         }
复制代码
Service方法:
  1. public async void ParseNotifyData(string timeStamp, string nonce, string content, string signature, string serialNumber)
  2.         {
  3.             var manager = new InMemoryCertificateManager();
  4.             var options = new WechatTenpayClientOptions()
  5.             {
  6.                 MerchantId = _config["MerchantId"],//商户号
  7.                 MerchantV3Secret = _config["MerchantV3Secret"],//商户API v3密钥
  8.                 MerchantCertificateSerialNumber = _config["MerchantCertificateSerialNumber"],//商户API证书序列号
  9.                 MerchantCertificatePrivateKey = FileContentHelper.ReadFileContent("apiclient_key.pem", Path.Combine(AppContext.BaseDirectory, "apiclient_key.pem")),//商户API证书私钥
  10.                 PlatformCertificateManager = manager // 证书管理器的具体用法请参阅下文的高级技巧与加密、验签有关的章节
  11.             };
  12.             var client = new WechatTenpayClient(options);
  13.             var request = new QueryCertificatesRequest();
  14.             var response = await client.ExecuteQueryCertificatesAsync(request);
  15.             if (response.IsSuccessful())
  16.             {
  17.                 response = client.DecryptResponseSensitiveProperty(response);
  18.                 foreach (var certificateModel in response.CertificateList)
  19.                 {
  20.                     manager.AddEntry(new CertificateEntry(certificateModel));
  21.                 }
  22.                 Log.Information("查询微信商户平台证书成功。");
  23.             }
  24.             bool valid = client.VerifyEventSignature(timeStamp, nonce, content, signature, serialNumber, out Exception? error);
  25.             if (valid)
  26.             {
  27.                 /* 将 JSON 反序列化得到通知对象 */
  28.                 /* 你也可以将 WechatTenpayEvent 类型直接绑定到 MVC 模型上,这样就不再需要手动反序列化 */
  29.                 var callbackModel = client.DeserializeEvent(content);
  30.                 if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
  31.                 {
  32.                     /* 根据事件类型,解密得到支付通知敏感数据 */
  33.                     var callbackResource = client.DecryptEventResource<TransactionResource>(callbackModel);
  34.                     string outTradeNumber = callbackResource.OutTradeNumber;
  35.                     string transactionId = callbackResource.TransactionId;
  36.                     Log.Information("回调返回的解密数据为{@callbackResource}", callbackResource);
  37.                     Console.WriteLine("订单 {0} 已完成支付,交易单号为 {1}", outTradeNumber, transactionId);
  38.                     Log.Information("outTradeNumber is " + outTradeNumber);
  39.                     Log.Information("outTradeNumber is " + transactionId);
  40.                     #region[存取支付结果]
  41.                     string boxCode = await GetBoxCodeByOrderNumber(Convert.ToInt64(outTradeNumber));
  42.                     //解绑机器;
  43.                     await _repositoryWrapper.UserBoxRepository.UnBindBox(boxCode);
  44.                     var orderId = await _repositoryWrapper.OrderRepository.QueryOrderIdByOrderNumberAsync(Convert.ToInt64(outTradeNumber));
  45.                     Log.Information("Update order pay result");
  46.                     await _repositoryWrapper.OrderRepository.SavePayResult(new OrderEntity()
  47.                     {
  48.                         OrderId = orderId,
  49.                         OutTradeNo = Int64.Parse(outTradeNumber),
  50.                         TradeState = callbackResource.TradeState,
  51.                         TradeStateDesc = callbackResource.TradeStateDescription,
  52.                         BankType = callbackResource.BankType,
  53.                         Total = callbackResource.Amount.Total,
  54.                         OpenId = callbackResource.Payer.OpenId,
  55.                         PayTotal = callbackResource.Amount.PayerTotal,
  56.                         TransactionId = callbackResource.TransactionId,
  57.                         SuccessTime = callbackResource.SuccessTime.ToString()
  58.                     });
  59.                     #endregion
  60.                     Log.Information("Update order pay status");
  61.                     if (!String.IsNullOrWhiteSpace(callbackResource.Attachment))
  62.                     {
  63.                         decimal walletAmount = 0m;
  64.                         if (Decimal.TryParse(callbackResource.Attachment, out walletAmount) && walletAmount > 0)
  65.                         {
  66.                             string weChatId = await _repositoryWrapper.OrderRepository.QueryWeChatIdByOrderId(orderId);
  67.                             await _repositoryWrapper.WalletRepository.PayUseWallet(new List<long>(), orderId, weChatId, walletAmount, false, true);
  68.                         }
  69.                     }
  70.                     await _repositoryWrapper.OrderRepository.UpdateOrderStatusByOrderNumberAsync(Convert.ToInt64(outTradeNumber), OrderStatus.PaySuccess.ToString("D"), (decimal)callbackResource.Amount.PayerTotal / 100);
  71.                     await _repositoryWrapper.RedPackageRepository.BatchUpdateRedPackeStatus(orderId, RedpackageUseEnum.Used);
  72.                 }
  73.                 else
  74.                 {
  75.                     /* 根据事件类型,解密得到支付通知敏感数据 */
  76.                     var callbackResource = client.DecryptEventResource<TransactionResource>(callbackModel);
  77.                     string outTradeNumber = callbackResource.OutTradeNumber;
  78.                     JObject obj = new();
  79.                     obj.Add("action", "payFail");
  80.                     var payFailStr = JsonConvert.SerializeObject(obj);
  81.                     await _repositoryWrapper.OrderRepository.UpdateOrderStatusByOrderNumberAsync(Convert.ToInt64(outTradeNumber), OrderStatus.PayFail.ToString("D"), (decimal)callbackResource.Amount.PayerTotal / 100);
  82.                 }
  83.             }
  84.             else
  85.             {
  86.                 Log.Error("Verify fail");
  87.                 Log.Error("Verify fail is {@error}", error);
  88.             }
  89.         }
复制代码
3、查询支付结果
  1. _orderService是我们业务中使用的service,使用方可自行根据自身业务删除。
复制代码
  1. public async Task<PayResultDto> QueryOrderPayStatus(OrderBaseDto orderBasic)
  2.         {
  3.             PayResultDto payResultDto = new PayResultDto();
  4.             string orderStatus = await _repositoryWrapper.OrderRepository.QueryOrderStatusAsync(orderBasic.OrderId);
  5.             if (orderStatus != null)
  6.             {
  7.                 OrderStatus orderEnumStatus = OrderStatus.UnDefine;
  8.                 if (System.Enum.TryParse(orderStatus, out orderEnumStatus) && orderEnumStatus == OrderStatus.PaySuccess)
  9.                 {
  10.                     payResultDto.PaySuccess = true;
  11.                     payResultDto.ContributionAmount = await _orderService.GetOrderContributionAsync(orderBasic.OrderId); ;
  12.                     return payResultDto;
  13.                 }
  14.             }
  15.             //string serialNumber = RSAUtility.ExportSerialNumber(@"D:\1630126864_20220905_cert\apiclient_cert.pem");
  16.             var manager = new InMemoryCertificateManager();
  17.             var options = new WechatTenpayClientOptions()
  18.             {
  19.                 MerchantId = _config["MerchantId"],//商户号
  20.                 MerchantV3Secret = _config["MerchantV3Secret"],//商户API v3密钥
  21.                 MerchantCertificateSerialNumber = _config["MerchantCertificateSerialNumber"],//商户API证书序列号
  22.                 MerchantCertificatePrivateKey = FileContentHelper.ReadFileContent("apiclient_key.pem", Path.Combine(AppContext.BaseDirectory, "apiclient_key.pem")),//商户API证书私钥
  23.                 PlatformCertificateManager = manager // 证书管理器的具体用法请参阅下文的高级技巧与加密、验签有关的章节
  24.             };
  25.             var client = new WechatTenpayClient(options);
  26.             /* 以 JSAPI 统一下单接口为例 */
  27.             //var userLogin = await _userService.UserLogin(orderBasic.JSCode);
  28.             Log.Information("OrderId is " + orderBasic.OrderId);
  29.             long orderNumber = await _repositoryWrapper.OrderRepository.QueryOrderNumberByOrderIdAsync(orderBasic.OrderId);
  30.             var request = new GetPayTransactionByOutTradeNumberRequest()
  31.             {
  32.                 OutTradeNumber = orderNumber.ToString(),
  33.                 MerchantId = _config["MerchantId"],//商户号
  34.                 WechatpayCertificateSerialNumber = _config["MerchantCertificateSerialNumber"]//商户API证书序列号
  35.             };
  36.             var response = await client.ExecuteGetPayTransactionByOutTradeNumberAsync(request);
  37.             Log.Information("response {@response}", response);
  38.             if (response.IsSuccessful() && response.TradeState == "SUCCESS")
  39.             {
  40.                 int payTotal = response.Amount.Total;
  41.                 Console.WriteLine("pay amount:" + payTotal);
  42.                 Log.Information($"QueryOrder order {orderNumber} payTotal is {payTotal}");
  43.                 if (payTotal > 0)
  44.                 {
  45.                     await _repositoryWrapper.OrderRepository.UpdateOrderStatusAsync(new OrderStatusDto()
  46.                     {
  47.                         OrderId = orderBasic.OrderId,
  48.                         OrderStatus = OrderStatus.PaySuccess.ToString("D"),
  49.                     });
  50.                     payResultDto.PaySuccess = true;
  51.                     payResultDto.ContributionAmount = await _orderService.GetOrderContributionAsync(orderBasic.OrderId);
  52.                     //payResultDto.Amount = payTotal/100m;
  53.                 }
  54.             }
  55.             else
  56.             {
  57.                 Log.Information($"response.RawStatus is {response.RawStatus}");
  58.                 Log.Information($"response.ErrorCode is {response.ErrorCode},response.ErrorMessage is {response.ErrorMessage}");
  59.                 //throw new Exception($"QueryOrder call return fail,orderNumber is {orderNumber}");
  60.             }
  61.             return payResultDto;
  62.         }
复制代码
 
出处:https://www.cnblogs.com/cby-love本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利.如果您觉得文章对您有帮助,可以点击文章右下角"推荐".您的鼓励是作者坚持原创和持续写作的最大动力!
来源:https://www.cnblogs.com/cby-love/archive/2023/01/05/17026424.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具