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中添加
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,
#spbill_create_ip: '192.168.0.102',
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
Rails.logger.info("========微信支付========")
result = Payment.wechat_pay(order.order_id) #order_id是商户平台生成的订单号。
logger.info "result======== #{result}"
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="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>
<table>
<% @qr.modules.each_index do |x| -%>
<tr>
<% @qr.modules.each_index do |y| -%>
<% if @qr.dark?(x,y) -%>
<td class="black"/>
<% else -%>
<% end -%>
<% end -%>
</tr>
<% end -%>
</table>
<%#= 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>
.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>
setInterval(function() {
//alert("Hello");
$.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>
6.用户扫码支付成功之后需要回调 ,app/controllers/interface/payments_controller.rb 接口添加回调方法。
Rails.logger.info "=============== 扫码支付成功,后台回调 =============="
result = Hash.from_xml(request.body.read)["xml"]
Rails.logger.info "success result =============== #{result.inspect} =============="
logger.info "======== 验证签名成功 ======= "
order_id = result["out_trade_no"].to_s
logger.info "订单编号: #{result["out_trade_no"]}-------"
order = Order.find_by_order_id(order_id)
logger.info "===== order is not blank ======"
time = Time.now.to_datetime
payed_price = result["total_fee"].to_f / 100.0
Rails.logger.info "== payed_price: #{payed_price}"
order.update_attributes(
:order_status => true,
:payed_price => payed_price,
:payed_at => time,
:payed_response => result.to_s
)
end
end
else
render :xml => {return_code: "FAIL", return_msg: "签名失败"}.to_xml(root: 'xml', dasherize: false)
end
end
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