由于轮子 https://github.com/jasl/wx_pay.git (感谢作者 @jasl) 使用比较良好,weixin_authorize(https://github.com/lanrion/weixin_authorize)目前暂不提供支付接口集成。
下面是使用 JSAPI 实现支付的使用说明:
Gemfile:
gem 'wx_pay', git: 'https://github.com/jasl/wx_pay.git'
your-app/config/initializers/wx_pay.rb:
# required
# WxPay.appid = Rails.application.secrets.app_id
WxPay.appid = "wxf5xxx"
WxPay.key = "xxxx"
WxPay.mch_id = "123123"
# optional - configurations for RestClient timeout, etc.
WxPay.extra_rest_client_options = {timeout: 2, open_timeout: 3}
# params = {
# body: '测试商品',
# out_trade_no: 'test003',
# total_fee: 1,
# spbill_create_ip: '127.0.0.1',
# notify_url: ERB::Util.url_encode('http://making.dev/notify'),
# trade_type: 'JSAPI',
# nonce_str: "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
# openid: "oah0RuOMkP2Kurp48bweSoaDqoEM"
# }
order.rb:
# 只有当微信支付时使用到,订单一旦确认(confirm),即进行获取
# {remote_ip: request.ip}
def set_prepay_id(options={})
return true if Rails.env.development?
return true if is_prepay_id_valid?
# 重新更新支付流水号
self.pay_serial_number = "#{number}-#{Time.current.to_i}"
unifiedorder = {
body: "#{SITE_NAME}-#{number}",
out_trade_no: pay_serial_number,
total_fee: (total_price * 100).to_i, # 需要转换为分
spbill_create_ip: options[:remote_ip] || '127.0.0.1',
notify_url: wx_notify_url,
trade_type: "JSAPI",
nonce_str: SecureRandom.hex,
openid: user.openid
}
Rails.logger.debug("unifiedorder_params: #{unifiedorder}")
res = WxPay::Service.invoke_unifiedorder(unifiedorder)
if res.success?
self.prepay_id = res["prepay_id"]
self.pre_pay_id_expired_at = Time.current + 2.hours
Rails.logger.debug("set prepay_id: #{self.prepay_id}")
self.save(validate: false)
else
Rails.logger.debug("set prepay_id fail: #{res}")
false
end
end
# {remote_ip: request.ip}
def get_prepay_id(options={})
set_prepay_id(options) if !is_prepay_id_valid?
prepay_id
end
def wx_notify_url
"#{Rails.application.secrets.host_url}pay_notify/weixin_notify"
end
# 总价
def total_price
self.item_total.to_f - self.promo_total.to_f
end
# 判断是否有效
def is_prepay_id_valid?
prepay_id.present? && Time.current.to_i <= pre_pay_id_expired_at.to_i
end
orders_controller.rb:
def show
@cash_voucher = @order.cash_voucher
@pay_p = {
appId: Rails.application.secrets.app_id,
timeStamp: Time.now.to_i.to_s,
nonceStr: SecureRandom.hex,
package: "prepay_id=#{@order.get_prepay_id(remote_ip: request.ip)}",
signType: "MD5"
}
@pay_sign = WxPay::Sign.generate(@pay_p)
end
views/orders/show.html.erb: 此处需要使用到 JS SDK 的 API,请查看: https://github.com/lanrion/weixin_authorize/wiki/js-sdk 用户进入这个页面时,如果预支付 ID 无效则重新进行获取,点击“立即支付”时,会发起支付。
.....
.....
<% if !@order.paid? && !@order.cancel? %>
<a href="javascript:;" class="to_pay btn btn-small">立即支付</a>
<% end %>
<%= content_for :javascript do %>
<%= render "layouts/weixin_js" if !Rails.env.development? %>
<script type="text/javascript">
var order_id = "<%= @order.id %>";
$(".to_pay").click(function(){
wx.chooseWXPay({
"timestamp": "<%= @pay_p[:timeStamp] %>",
"nonceStr": "<%= @pay_p[:nonceStr] %>",
"package": "<%= @pay_p[:package] %>",
"signType": "<%= @pay_p[:signType] %>",
"paySign": "<%= @pay_sign %>", // 支付签名
success: function (res) {
window.location.href = "/orders/" + order_id + "/pay_success";
}
});
});
</script>
<% end %>
routes.rb:
resource :pay_notify, only: [] do
collection do
post :weixin_notify
post :weixin_exception_notify
end
end
controllers:
class PayNotifiesController < ActionController::Base
# 支付异步通知
def weixin_notify
result = Hash.from_xml(request.body.read)["xml"]
Rails.logger.debug("weixin notify: #{result}")
if WxPay::Sign.verify?(result)
pay_serial_number = result["out_trade_no"]
order = Order.find_by(pay_serial_number: pay_serial_number)
order.paid_amount = result["total_fee"]
order.state = "paid"
order.pay_logs.new(
pay_type: "weixin",
trade_type: result[:trade_type],
log: result
)
order.save(validate: false)
# 支付成功后,减库存
Rails.logger.debug("支付成功后,减库存")
render xml: {
return_code: "SUCCESS"
}.to_xml(root: 'xml', dasherize: false)
else
render xml: {
return_code: "SUCCESS",
return_msg: "签名失败"
}.to_xml(root: 'xml', dasherize: false)
end
end
# 接收 报警
# http://www.cnblogs.com/txw1958/p/weixin-payment-solution.html
def weixin_exception_notify
result = Hash.from_xml(request.body.read)["xml"]
ServiceNotify.create(service_type: "weixin", content: result)
end
end
如有问题,可以往: http://weixin-dev.com/topics 提问,又或者前往 https://github.com/lanrion/weixin_authorize/ 提问。
原文:https://github.com/lanrion/weixin_authorize/wiki/js-api-wx-pay