Project

wechat_pay

0.03
No commit activity in last 3 years
No release in over 3 years
微信支付
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.6
~> 1.3
>= 0

Runtime

~> 1.6.7
 Project Readme

WechatPay

Attention: this gem is developed under v2.x API, if you using v3.X API, you probably need wx_pay gem

微信支付:
https://open.weixin.qq.com/cgi-bin/frame?t=home/pay_tmpl&lang=zh_CN
Official document

It contains:

  • generate access-token
  • app payment
  • js payment
  • native payment
  • verify notify
  • deliver notify
  • order query

MRI Ruby 2.0.0 and newer are supported. 1.9.2 should work as well but not tested.

Installation

Add this line to your application's Gemfile:

gem 'wechat_pay'

And then execute:

$ bundle

Or install it yourself as:

$ gem install wechat_pay

Usage

Config

WechatPay.app_id       = 'YOUR_APP_ID'
WechatPay.app_secret   = 'YOUR_APP_SECRET'
WechatPay.pay_sign_key = 'YOUR_PAY_SIGN_KEY'
WechatPay.partner_id   = 'YOUR_PARTNER_ID'
WechatPay.partner_key  = 'YOUR_PARTNER_KEY'

Access Token

WechatPay::AccessToken.generate # => { access_token: 'ACCESS_TOKEN', expires_in: 7200 }

Your should cache the access_token, see http://mp.weixin.qq.com/wiki/index.php...

You may wanna do something like this in Rails:

Rails.cache.fetch(:wechat_pay_access_token, expires_in: 7200.seconds, raw: true) do
  WechatPay::AccessToken.generate[:access_token]
end

App Payment

# Please keep in mind that all key MUST be Symbol
params = {
  body:             'body',
  traceid:          'traceid',      # Your user id
  out_trade_no:     'out_trade_no', # Your order id
  total_fee:        '100',          # 注意:单位是分,不是元
  notify_url:       'http://your_domain.com/notify',
  spbill_create_ip: '192.168.1.1'
}

WechatPay::App.payment('ACCESS_TOKEN', params)
# =>
#   {
#     nonce_str:  'noncestr',
#     package:    'Sign=WXpay',
#     partner_id: 'partner_id',
#     prepay_id:  'prepay_id',
#     timestamp:  '1407165191',
#     sign:       'sign'
#   }

Native Payment

generate url
WechatPay::Native.payment_url('OUT_TRADE_NO')
# => "weixin://wxpay/bizpayurl?sign=SIGN&productid=..."
verify and generate package
# example in rails controller
def package
  request_data = Hash.from_xml(request.body.read)['xml'].symbolize_keys
  app_signature = request_data[:AppSignature]
  verify_params = {
    productid:   request_data[:ProductId],
    timestamp:   request_data[:TimeStamp],
    noncestr:    request_data[:NonceStr],
    openid:      request_data[:OpenId],
    issubscribe: request_data[:IsSubscribe]
  }
  verified = WechatPay::Native.verify?(app_signature, verify_params)

  if verified
    # you may wanna find the order by `request_data['ProductId']`
    package_params = {
      body:             'body',
      out_trade_no:     'out_trade_no',
      total_fee:        '1',
      notify_url:       'http://your_domain.com/wechat_pay/notify',
      spbill_create_ip: request.remote_ip
    }
    @data = WechatPay::Native.package('0', 'ok', package_params)
    render "package.xml.erb"
  else
    head(200)
  end
end

# package.xml.erb
<xml>
  <AppId><%= @data[:app_id] %></AppId>
  <NonceStr><%= @data[:nonce_str] %></NonceStr>
  <TimeStamp><%= @data[:timestamp] %></TimeStamp>
  <Package><%= @data[:package] %></Package>
  <RetCode><%= @data[:ret_code] %></RetCode>
  <RetErrMsg><%= @data[:ret_err_msg] %></RetErrMsg>
  <SignMethod><%= @data[:sign_method] %></SignMethod>
  <AppSignature><%= @data[:app_signature] %></AppSignature>
</xml>

JS Payment

In Controller
params = {
  body:             'body',
  out_trade_no:     'out_trade_no'
  total_fee:        '100'
  notify_url:       'http://your_domain.com/notify',
  spbill_create_ip: '192.168.1.1'
}

@order_params = WechatPay::JS.payment(params)

# =>
#    {
#      app_id:    "app_id",
#      timestamp: "1407165191",
#      nonce_str: "noncestr",
#      package:   "Sign=WXpay",
#      pay_sign:  "pay_sign",
#      sign_type: 'SHA1'
#    }
In View
<%= link_to "wechat_payment_btn", "javascript:void(0)", id: "wechatPaymentBtn" %>

<%= javascript_tag do %>
  var orderParams = { 
    appId:     "<%= @order_params[:app_id] %>",
    timeStamp: "<%= @order_params[:timestamp] %>",
    nonceStr:  "<%= @order_params[:nonce_str] %>",
    package:   "<%= @order_params[:package] %>",
    paySign:   "<%= @order_params[:pay_sign] %>",
    signType:  "<%= @order_params[:sign_type] %>"
  };
  document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
    $('#wechatPaymentBtn').click(function() {
      WeixinJSBridge.invoke('getBrandWCPayRequest', orderParams, function(res) {
        if (res.err_msg == "get_brand_wcpay_request:ok") {
          alert('pay for success!');
        } else {
          alert(res.err_msg);
        }
      });
    });
  }, false);
<% end %>

Verify notify

# Rails example
# for app, js and native
def notify
  # except :controller_name, :action_name, :host, etc.
  notify_params = params.except(*request.path_parameters.keys)

  if WechatPay::Notify.verify?(notify_params)
    # Valid notify status
    if params[:trade_state] == '0'
      # Code your business logic
    end
    render text: 'success'
  else
    render text: 'error'
  end
end

def warning_notify
  attrs = Hash.from_xml(request.ody.read)['xml']
              .transform_keys{ |k| k.downcase.to_sym }
  attrs.delete(:signmethod)
  app_signature = attrs.delete(:appsignature)

  if WechatPay::Notify::Warning.verify?(app_signature, attrs)
    # Code your business logic
  end

  head(200)
end

Deliver Notify

# Please keep in mind that all key MUST be Symbol
params = {
  openid: 'openid',
  transid: 'transid',
  out_trade_no: 'out_trade_no',
  deliver_msg: 'ok',              # optional, default is 'ok'
  deliver_status: '1',            # optional, default is '1'
  deliver_timestamp: '1410105134' # optional, default is `Time.now.to_i.to_s`
}

WechatPay::DeliverNotify.request('ACCESS_TOKEN', params)
# => { errcode: 0, errmsg: 'ok' }

Order Query

WechatPay::OrderQuery.request('ACCESS_TOKEN', 'YOUR_OUT_TRADE_NO')
# => { errcode: 0, errmsg: 'ok', order_info: { ret_code: 0, ... } }

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

License

WTFPL