海哥 发表于 2023-1-5 06:27:36

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

本实例使用了工具包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>
      
      public async Task WeChatPayNotifyUrl(
             string timestamp,
             string nonce,
             string signature,
             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;
      } 
出处:https://www.cnblogs.com/cby-love本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利.如果您觉得文章对您有帮助,可以点击文章右下角"推荐".您的鼓励是作者坚持原创和持续写作的最大动力!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 微信支付--JSAPI支付(微信小程序和微信公众号支付都可以采用该方式)