rails实现pc商城的微信扫码支付(native wechat pay)

June 05, 2018 19:24
访问量:528
摘要:rails实现pc商城的微信扫码支付(native wechat pay)

pc商城扫码支付,调用微信统一下单接口,参考微信官方的开发文档 调用统一下单接口进行支付。

在这之前先把装备工作做好,微信需要申请的各种账号,商户在微信公众平台(申请扫码支付),审核通过之后登录账号能获得一些参数。

邮件中参数 API参数名 详细说明
APPID appid appid是微信公众账号或开放平台APP的唯一标识,在公众平台申请公众账号或者在开放平台申请APP账号后,微信会自动分配对应的appid,用于标识该应用。可在微信公众平台-->开发-->基本配置里面查看,商户的微信支付审核通过邮件中也会包含该字段值。
微信支付商户号 mch_id 商户申请微信支付后,由微信支付分配的商户收款账号。
API密钥 key 交易过程生成签名的密钥,仅保留在商户系统和微信支付后台,不会在网络中传播。商户妥善保管该Key,切勿在网络中传输,不能在其他客户端中存储,保证key不会被泄漏。商户可根据邮件提示登录微信商户平台进行设置。也可按一下路径设置:微信商户平台(pay.weixin.qq.com)-->账户中心-->账户设置-->API安全-->密钥设置
Appsecret secret AppSecret是APPID对应的接口密码,用于获取接口调用凭证access_token时使用。在微信支付中,先通过OAuth2.0接口获取用户openid,此openid用于微信内网页支付模式下单接口使用。可登录公众平台-->微信支付,获取AppSecret(需成为开发者且帐号没有异常状态)。

准备工作好之后可以开始集成微信支付了。

1.微信支付过程中最麻烦的就是 签名 验证签名的这一列的过程, 所以我们使用已有的轮子来帮我们解决这个问题, https://github.com/jasl/wx_pay 。在gemfile中添加:

gem 'wx_pay', :github => 'jasl/wx_pay' 
gem 'rqrcode', '0.10.1'      #生成二维码的gem

2.bundle,然后在settings.yml中添加上面申请的一些参数

#微信支付参数
wechat_pay:
  app_id: "xxxxxxxxxxxx"
  app_key: "xxxxxxxxxxxxxxxxxxxx"
  mch_id: "xxxxxxxxx"

3.model/payment.rb 中添加向微信服务器请求支付的方法, 以及根据微信返回的参数生成二维码的方法。

  def self.wechat_pay(order_id)
    logger.info "=======开始调用微信支付========"
    order = Order.find_by_order_id(order_id)
    artwork_id = order.buy_goods.first.artwork_id
    order_name = Artwork.find(artwork_id).name

    params = {
      body: order_name,
      out_trade_no: order_id,
      total_fee: (order.total_cost * 100).to_i,
      notify_url: 'http://shop.art-bank.net/interface/payments/wx_pay_notify',
      trade_type: 'NATIVE', # could be "JSAPI", "NATIVE" or "APP",
    }
    result = WxPay::Service.invoke_unifiedorder params
  end

  def self.generate_qr_code(code_url, order_id)
    logger.info "========开始生成用户支付的二维码========"
    qrcode = RQRCode::QRCode.new(code_url)
  end

4.在对应的controller, 我这里是在orders_controller.rb 中添加调用微信扫码支付的方法。

  def  go_wechat_pay
    result = Payment.wechat_pay(order.order_id)  #order_id是商户平台生成的订单号。
    redirect_to wx_pay_qrcode_orders_path(:code_url => result["code_url"], :order_id => order.order_id)
  end

  def wx_pay_qrcode
    @qr = RQRCode::QRCode.new(params[:code_url])

    order = Order.find_by_order_id(params[:order_id])
    artwork_id = order.buy_goods.first.artwork_id
    @order_name = Artwork.find(artwork_id).name

    @total_cost = Order.find_by_order_id(params[:order_id]).total_cost if params[:order_id].present?
  end

5.对应的app/views/orders/wx_pay_qrcode.html.erb,直接跳到二维码页面,如下图。

输入图片说明

<div class="pay_cost">
  <div class="logo_image" style="">
    <%= image_tag "http://siweitech.b0.upaiyun.com/cms/2018-01-10-WePayLogo.png", style: "width: 250px;" %>
  </div>
  <div style="padding: 20px; border-bottom: 1px solid gainsboro;">
    <span class="order_detail">
      订单号: <span class="price"><%= params[:order_id] %></span>
    </span>
    <span class="order_detail">
      订单名称: <span class="price"><%= @order_name  %></span>
    </span>
    <span class="order_detail">
      支付金额: <span class="price"><%= @total_cost %></span>
    </span>
  </div>
  <div class="qr_code">
    <table>
      <% @qr.modules.each_index do |x| -%>
        <tr>
          <% @qr.modules.each_index do |y| -%>
            <% if @qr.dark?(x,y) -%>
              <td class="black"/>
            <% else -%>
              <td class="white"/>
            <% end -%>
          <% end -%>
        </tr>
      <% end -%>
    </table>
    <div style="text-align: center; margin:40px 0;">
      <%#= image_tag "http://siweitech.b0.upaiyun.com/cms/2018-01-10-%E8%AF%B4%E6%98%8E%E6%96%87%E5%AD%97.png", style:
      <span class="order_detail">
        请使用<span class="wx_text">微信扫码二维码</span>完成支付
      </span>
    </div>
  </div>
</div>

<style type="text/css">
.qr_code {
  margin: 80px;
}
.logo_image {
  text-align: center;
  padding: 25px;
  background: #f3f3f3;
}
.order_detail {
  margin: 0 70px;
  color: #9E9E9E;
}
.pay_cost{
  font-size: 18px;
  line-height: 60px;
  margin: 20px 0;
  text-align: center;
  border: 2px solid gainsboro;
}
.price{
  font-size: 20px;
  margin-left: 10px;
  color: #0fbf0f;
}
.wx_text {
  font-size: 20px;
  margin-left: 0px;
  color: #f56f2e;
}
table {
  border-width: 0;
  border-style: none;
  border-color: #0000ff;
  border-collapse: collapse;
}
  td {
    border-width: 0;
    border-style: none;
    border-color: #0000ff;
    border-collapse: collapse;
    padding: 0;
    margin: 0;
    width: 7px;
    height: 7px;
  }
  td.black { background-color: #000; }
  td.white { background-color: #fff; }
</style>

6.支付成功之后 订单状态会更改为已支付,页面上使用ajax发起请求。轮询来判断支付状态app/views/orders/wx_pay_qrcode.html.erb

<script>
setInterval(function() {
  $.post("/interface/payments/is_wxpay_success",
      {
        order_id: <%= params[:order_id] %>
      },
      function(data) {
        if (data.is_pay_success == "yes") {
          window.location.href = "/orders/alipay_success?order_id=<%= params[:order_id] %>"
        }
      })
}, 2000);
</script>

7.支付成功之后 订单状态会更改为 已支付,页面上使用ajax发起请求。轮询来判断支付状态。

  def is_wxpay_success
    order = Order.find_by_order_id(params[:order_id])
    if order.order_status
      logger.info("======用户扫码支付成功=====")

      render :json => {
        :is_pay_success => "yes"
      }
    else
      logger.info("======用户还未支付=====")
      render :json => {
        :is_pay_success => "no"
      }
    end
  end

8.用户扫码支付成功之后需要回调 ,app/controllers/interface/payments_controller.rb 接口添加回调方法。

  def wx_pay_notify
    Rails.logger.info "=============== 扫码支付成功,后台回调 =============="
    result = Hash.from_xml(request.body.read)["xml"]
    if WxPay::Sign.verify?(result)
      logger.info "======== 验证签名成功 ======= "
      order_id = result["out_trade_no"].to_s
      logger.info "订单编号: #{result["out_trade_no"]}-------"
      order = Order.find_by_order_id(order_id)
      unless order.blank?
        time = Time.now.to_datetime
        payed_price = result["total_fee"].to_f / 100.0
        Order.transaction do
            order.update_attributes(
              :order_status => true,
              :payed_price => payed_price,
              :payed_at => time,
              :payed_response => result.to_s
              :payed_response => result.to_s
            )
        end
      end
      render :xml => {return_code: "SUCCESS"}.to_xml(root: 'xml', dasherize: false)
    else
      render :xml => {return_code: "FAIL", return_msg: "签名失败"}.to_xml(root: 'xml', dasherize: false)
    end
  end

评论

暂无相关评论,快来抢占沙发吧!
评论框离家出走了,点击找回!
昵称
邮箱
网站
昵称
邮箱
网站