Ruby on Rails在Ping ++ 平台实现支付
本地数据库创建订单表。
建议包含以下字段,参考官方API(https://pingxx.com/document/api#api-c-new):
order_no:required
商户订单号,适配每个渠道对此参数的要求,必须在商户系统内唯一。 alipay:1-64位, wx:1-32位, bfb:1-20位, upacp:8-40位, yeepay_wap:1-50位, jdpay_wap:1-30位, cnp_u:8-20位, cnp_f:8-20位, 推荐使用8-20位,要求数字或字母,不允许特殊字符
app[id]:required
支付使用的app对象的id,请登陆管理平台查看。
subject:required
商品的标题,该参数最长为32个Unicode字符, 银联全渠道(upacp/upacp_wap)限制在32个字节。
body:required
商品的描述信息,该参数最长为128个Unicode字符, yeepay_wap对于该参数长度限制为100个Unicode字符。
channel:required
支付使用的第三方支付渠道(更多请参考api) alipay:支付宝手机支付 alipay_wap:支付宝手机网页支付 alipay_qr:支付宝扫码支付 alipay_pc_direct:支付宝PC网页支付 apple_pay:ApplePay bfb:百度钱包移动快捷支付 bfb_wap:百度钱包手机网页支付 wx:微信支付 wx_pub:微信公众账号支付 wx_pub_qr:微信公众账号扫码支付 jdpay_wap:京东手机网页支付
amount:required
订单总金额,单位为对应币种的最小货币单位, 例如:人民币为分(如订单总金额为1元,此处请填100)。
client_ip:required
发起支付请求终端的IP地址,格式为IPV4,如:127.0.0.1。
以上是在ping++平台创建订单时需要的参数
以下是在ping++平台创建订单成功以及付款成功回调的参数
paid:支付状态,默认为false refunded:退款状态,默认为false time_paid:付款时间 time_refunded:退款时间 charge_no:返回的charge编号 transaction_no:交易号
步骤:
1.本地创建一条订单记录
defcreate_order
#获取参数 #判断参数合法性 order=Order.new #保存订单信息,注意subject以及body的长度 #生成订单号并保存 order_no=(Time.now.to_formatted_s(:number)).to_s 6.times{order_no<<rand(10).to_s} order.order_no=order_no #获取ip并保存 order.client_ip=request.remote_ip iforder.save #返回成功信息 else render_failure(order.errors.messages.first[1][0]) end end
2.执行支付
现在ping++平台创建一条记录
1.在order.rb文件中新建一个方法
defpay_url #获取api_key以及app_id Pingpp.api_key=PingPlusPlus.get_ping_settings["PING_API_KEY"] app_id=PingPlusPlus.get_ping_settings["PING_APP_ID"] #不同支付渠道的回调地址 caseself.channel when"alipay" extra={ } when"wx" extra={ } end #ping++平台新建一个订单 begin charge=Pingpp::Charge.create( :order_no=>self.order_no, :app=>{:id=>app_id}, :channel=>self.channel, :amount=>self.amount.round(2)*100.to_i, :client_ip=>self.client_ip, :currency=>"cny", :subject=>self.subject[0..31], :body=>self.body[0..127], :extra=>extra ) returncharge rescuePingpp::PingppError=>error logger.error'ping++平台创建订单失败' logger.errorerror.http_body returnfalse end end
2.调用pay_url方法创建订单,返回给客户端charge对象,客户端拿着charge对象去ping++平台支付
defconfirm_and_payment order_no=params[:order_no] channel=params[:channel] iforder_no.blank?||channel.blank? render_failure("参数不完整!")andreturn end order=Order.where(order_no:order_no).first iforder.blank? render_failure("订单不存在!")andreturn end charge=order.pay_url ifcharge==false render_failure("订单支付失败!")andreturn else order.update_attribute(:charge_no,(JSON.parsecharge.to_s)['id']) render(:json=>charge) end end
异步通知更新付款结果
defnotify status=400 #判断请求是否有ping++的签名信息 ifrequest.headers['x-pingplusplus-signature'].blank? status=401 logger.debug'【报哪家】:======付款回调请求来源错误!!!!!' return end #获取签名信息 raw_data=request.body.read ifrequest.headers['x-pingplusplus-signature'].is_a?(Array) signature=request.headers['x-pingplusplus-signature'][0].to_s else signature=request.headers['x-pingplusplus-signature'].to_s end #获取「Webhooks验证Ping++公钥」 pub_key_path="#{Rails.root}/config/rsa_public_key.pem" ifverify_signature(raw_data,signature,pub_key_path) #处理接收的结果 event=JSON.parse(raw_data) #付款成功 ifevent["type"]=='charge.succeeded' #开发者在此处加入对支付异步通知的处理代码 order_no=event['data']['object']['order_no'] order=Order.where(order_no:order_no).first order_from=order.status iforder.present? #更新字段 order.paid=event['data']['object']['paid'] iforder.save status=200 else status=500 end else logger.debug'数据库没有该条记录!' end #退款成功 elsifevent['type']=='refund.succeeded' #开发者在此处加入对退款异步通知的处理代码 order_no=event['data']['object']['order_no'] order=Order.where(order_no:order_no).first iforder.present? #更新字段 order.time_refunded=Time.at(event['data']['object']['time_succeed']) iforder.save status=200 else status=500 end else logger.debug'数据库没有该条记录!' end else logger.debug'付款回调返回未知操作!' end else logger.debug'付款回调请求来源错误!' status=403 end render:nothing=>true,:status=>status end