Ruby on Rails在Ping ++ 平台实现支付

所属分类: 脚本专栏 / ruby专题 阅读数: 1227
收藏 0 赞 0 分享

本地数据库创建订单表。

建议包含以下字段,参考官方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:Apple Pay
  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.本地创建一条订单记录

 def create_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
 
 if order.save
  #返回成功信息
 else
  render_failure(order.errors.messages.first[1][0])
 end
 end

2.执行支付

现在ping++ 平台创建一条记录
1.在order.rb文件中新建一个方法

 def pay_url
  #获取api_key以及app_id
  Pingpp.api_key = PingPlusPlus.get_ping_settings["PING_API_KEY"]
  app_id = PingPlusPlus.get_ping_settings["PING_APP_ID"]
  #不同支付渠道的回调地址
  case self.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
     )
   
   return charge
  rescue Pingpp::PingppError => error
    logger.error 'ping++平台创建订单失败'
    logger.error error.http_body
    return false
  end
 end

2.调用pay_url方法创建订单,返回给客户端charge对象,客户端拿着charge对象去ping++ 平台支付

 def confirm_and_payment
  order_no = params[:order_no]
  channel = params[:channel]
  if order_no.blank? || channel.blank?
   render_failure("参数不完整!") and return
  end
 
  order = Order.where(order_no: order_no).first
  if order.blank?
    render_failure("订单不存在!")and return
  end

  charge = order.pay_url
  if charge == false
   render_failure("订单支付失败!") and return
  else
   order.update_attribute(:charge_no ,(JSON.parse charge.to_s)['id'])
   render(:json => charge)
  end
 end

异步通知更新付款结果

 def notify

  status = 400

  #判断请求是否有ping++的签名信息
  if request.headers['x-pingplusplus-signature'].blank?
   status = 401
   logger.debug '【报哪家】:======付款回调请求来源错误!!!!!'
   return
  end 

  #获取签名信息
  raw_data = request.body.read
  if request.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"
  if verify_signature(raw_data, signature, pub_key_path)
    #处理接收的结果
    event = JSON.parse(raw_data) 
    #付款成功
    if event["type"] == 'charge.succeeded'

    # 开发者在此处加入对支付异步通知的处理代码
    order_no = event['data']['object']['order_no']
    order = Order.where(order_no: order_no).first
    order_from = order.status 
    if order.present?
     #更新字段
     order.paid = event['data']['object']['paid'] 
     if order.save
       status = 200
     else
      status = 500
     end
    else
      logger.debug '数据库没有该条记录!'
    end

    #退款成功
   elsif event['type'] == 'refund.succeeded'

     # 开发者在此处加入对退款异步通知的处理代码
    order_no = event['data']['object']['order_no']
    order = Order.where(order_no: order_no).first
    if order.present?
     #更新字段
     order.time_refunded = Time.at(event['data']['object']['time_succeed'])
     if order.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

更多精彩内容其他人还在看

Ruby中用线程实现经典的生产者消费者问题代码实例

这篇文章主要介绍了Ruby中用线程实现经典的生产者消费者问题代码实例,本文直接给出实现代码和运行效果,需要的朋友可以参考下
收藏 0 赞 0 分享

Ruby中常用的字符串处理函数使用实例

这篇文章主要介绍了Ruby中常用的字符串处理函数使用实例,本文总结了Ruby中最常用的字符串处理函数,如返回字符串的长度、判断字符串中是否包含另一个串、字符串插入、字符串分隔、默认分隔符为空格等内容,需要的朋友可以参考下
收藏 0 赞 0 分享

Windows下ruby语言安装教程

这篇文章主要介绍了Windows下ruby语言安装教程,本文使用rubyinstaller提供的安装包安装,并给出图文说明,非常简单,需要的朋友可以参考下
收藏 0 赞 0 分享

ruby环境中自动编译sass教程

这篇文章主要介绍了ruby环境中自动编译sass教程,本文讲解了ruby环境的安装、sass环境的安装以及sass的常用编译命令使用示例,需要的朋友可以参考下
收藏 0 赞 0 分享

Ruby中相等性判断的4种方法

这篇文章主要介绍了Ruby中相等性判断的4种方法,本文讲解了“==” 最常见的相等性判断、“===” 用于 case 语句的相容判断、“equal?” 相同对象判断、“eql?” 对象 hash 值判断等内容,需要的朋友可以参考下
收藏 0 赞 0 分享

Rails中使用MySQL分区表一个提升性能的方法

这篇文章主要介绍了Rails中使用MySQL分区表一个提升性能的方法,本文总结出了一个简单的方法实现避免扫描全部的分区表,从而提升性能,需要的朋友可以参考下
收藏 0 赞 0 分享

Rails应用程序中同时修改操作冲突问题的解决方案

这篇文章主要介绍了Rails应用程序中同时修改操作冲突问题的解决方案,本文讲解使用Rails 的 乐观锁解决这个问题并给出了代码救命,需要的朋友可以参考下
收藏 0 赞 0 分享

Ruby中的p和puts的使用区别浅析

这篇文章主要介绍了Ruby中的p和puts的使用区别浅析,本文用一个实例讲解了它们之间的区别,并总结出结论,需要的朋友可以参考下
收藏 0 赞 0 分享

Ruby中的block、proc、lambda区别总结

这篇文章主要介绍了Ruby中的block、proc、lambda区别总结,本文讲解了yield 和 block call 的区别、block 和 proc、lambda 的区别、proc 和 lambda 的区别,需要的朋友可以参考下
收藏 0 赞 0 分享

Ruby的运算符和语句优先级介绍

这篇文章主要介绍了Ruby的运算符和语句优先级介绍,本文先是给出了一些小例子来验证运算符和语句优先级,然后总结出一个优先级表,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多