1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

Ruby on RailsでPing ++プラットフォームでの決済を実現

2022-02-01 10:22:36

注文テーブルを作成するためのローカルデータベース。

公式APIを参考に、以下のフィールドを含めることが推奨されています( https://pingxx.com/document/api#api-c-new ).

注文番号:必須

  Merchant order number, adapted to the requirements of each channel for this parameter, must be unique in the merchant system.
  alipay: 1-64 bits.
  wx: 1-32 bits.
  bfb: 1-20 bits.
  upacp: 8-40 bits.
  yeepay_wap: 1-50 bits.
  jdpay_wap:1-30 bits.
  cnp_u:8-20 bits.
  cnp_f:8-20 bits.
  Recommended 8-20 bits, requires numbers or letters, no special characters allowed


app[id]:必須

 The id of the app object used for payment, please login to the admin panel to see it.


件名:必須

  The title of the product, this parameter is limited to a maximum of 32 Unicode characters.
  UnionPay Omnichannel (upacp/upacp_wap) is limited to 32 bytes.


本文:必須

 The description of the product, the maximum length of this parameter is 128 Unicode characters.
 yeepay_wap is limited to 100 Unicode characters for this parameter.


チャンネル:必須

 Third-party payment channels used for payment (please refer to api for more)
  alipay:Alipay mobile payment
  alipay_wap:Alipay mobile web payment
  alipay_qr:Alipay sweep code payment
  alipay_pc_direct:Alipay PC web payment
  apple_pay:Apple Pay
  bfb:Baidu Wallet Mobile Quick Payment
  bfb_wap:Baidu Wallet Mobile Web Payment   
  wx:微信支付
  wx_pub:微信公众账号支付
  wx_pub_qr:微信公众账号扫码支付
  jdpay_wap:京东手机網頁支付


amount: 必須

 The total amount of the order, in the smallest currency unit of the corresponding currency.
 For example, RMB is cents (if the total amount of the order is 1 yuan, enter 100 here).


client_ip: 必須

  The IP address of the endpoint initiating the payment request, in IPV4 format, e.g. 127.0.0.1.



ping++プラットフォームで注文を作成するために必要なパラメータは、以下のとおりです。

ping++プラットフォームで注文を正常に作成し、支払いコールバックを正常に行うには、以下のパラメータが必要です。

paid : Payment status, default is false
refunded : refund status, default is false
time_paid : time of payment
time_refunded : refunded time
charge_no: the charge number returned
transaction_no : transaction number


ステップ

1. ローカルでオーダーレコードを作成する

 def create_order

 #Get the parameters  
 #Determine the legitimacy of the parameter 
 
 order = Order.new
 #Save the order information, note the subject and the length of the body
 #Generate order number and save it
 order_no = (Time.now.to_formatted_s(:number)).to_s
 6.times{ order_no<<rand(10).to_s }
 order.order_no = order_no

 # Get the ip and save it
 order.client_ip = request.remote_ip
 
 if order.save
  # return success message
 else
  render_failure(order.errors.messages.first[1][0])
 end
 end



2. 決済の実行

ここで、ping++プラットフォームは、レコードを作成します。
1. order.rb ファイルに新しいメソッドを作成します。

 def pay_url
  # Get api_key and app_id
  Pingpp.api_key = PingPlusPlus.get_ping_settings["PING_API_KEY"]
  app_id = PingPlusPlus.get_ping_settings["PING_APP_ID"]
  # callback address for different payment channels
  case self.channel
    when "alipay"
    extra = {
   }
    when "wx"
    extra = {
   } 
   end
  #ping++ platform to create a new order
  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++ platform failed to create order'
    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("Parameter incomplete! ") and return
  end
 
  order = Order.where(order_no: order_no).first
  if order.blank?
    render_failure("Order does not exist! ") and return
  end

  charge = order.pay_url
  if charge == false
   render_failure("Order payment failed! ") and return
  else
   order.update_attribute(:charge_no ,(JSON.parse charge.to_s)['id'])
   render(:json => charge)
  end
 end



決済結果更新のための非同期通知

 def notify

  status = 400

  # Determine if the request has the ping++ signature information
  if request.headers['x-pingplusplus-signature'].blank?
   status = 401
   logger.debug '[report which]: ====== payment callback request source error !!!!!'
   return
  end 

  # Get signature information
  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
  
  # Get "Webhooks verify Ping++ public key"
  pub_key_path = "#{Rails.root}/config/rsa_public_key.pem"
  if verify_signature(raw_data, signature, pub_key_path)
    # Process the received result
    event = JSON.parse(raw_data) 
    #Payment success
    if event["type"] == 'charge.succeeded'

    # The developer adds code to handle asynchronous notifications for payments here
    order_no = event['data']['object']['order_no']
    order = Order.where(order_no: order_no).first
    order_from = order.status 
    if order.present?
     # update field
     order.paid = event['data']['object']['paid'] 
     if order.saved
       status = 200
     else
      status = 500
     end
    else
      logger.debug 'The database does not have this record!
    end

    # Refunds are successful
   elsif event['type'] == 'refund.refunded'

     # The developer adds code to handle asynchronous notifications of refunds here
    order_no = event['data']['object']['order_no']
    order = Order.where(order_no: order_no).first
    if order.present?
     # update field
     order.time_refunded = time.at(event['data']['object']['time_succeed'])
     if order.save
      status = 200
     else
      status = 500
     end
    else
      logger.debug 'The database does not have this record!
    end

   else
    logger.debug 'The payment callback returned an unknown operation!
   end

   else
    logger.debug 'The payment callback request came from an incorrect source!
    status = 403
   end
   render :nothing => true, :status => status
 end