Ruby on Rails在Ping ++ 平臺實現(xiàn)支付
本地數(shù)據(jù)庫創(chuàng)建訂單表。
建議包含以下字段,參考官方API( https://pingxx.com/document/api#api-c-new):
order_no:required
商戶訂單號,適配每個渠道對此參數(shù)的要求,必須在商戶系統(tǒng)內(nèi)唯一。 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 位,要求數(shù)字或字母,不允許特殊字符
app[id]:required
支付使用的 app 對象的 id,請登陸管理平臺查看。
subject:required
商品的標題,該參數(shù)最長為 32 個 Unicode 字符, 銀聯(lián)全渠道(upacp/upacp_wap)限制在 32 個字節(jié)。
body:required
商品的描述信息,該參數(shù)最長為 128 個 Unicode 字符, yeepay_wap 對于該參數(shù)長度限制為 100 個 Unicode 字符。
channel:required
支付使用的第三方支付渠道(更多請參考api) alipay:支付寶手機支付 alipay_wap:支付寶手機網(wǎng)頁支付 alipay_qr:支付寶掃碼支付 alipay_pc_direct:支付寶 PC 網(wǎng)頁支付 apple_pay:Apple Pay bfb:百度錢包移動快捷支付 bfb_wap:百度錢包手機網(wǎng)頁支付 wx:微信支付 wx_pub:微信公眾賬號支付 wx_pub_qr:微信公眾賬號掃碼支付 jdpay_wap:京東手機網(wǎng)頁支付
amount: required
訂單總金額, 單位為對應(yīng)幣種的最小貨幣單位, 例如:人民幣為分(如訂單總金額為 1 元,此處請?zhí)?100)。
client_ip: required
發(fā)起支付請求終端的 IP 地址,格式為 IPV4,如: 127.0.0.1。
以上是在ping++ 平臺創(chuàng)建訂單時需要的參數(shù)
以下是在ping++ 平臺創(chuàng)建訂單成功以及付款成功回調(diào)的參數(shù)
paid :支付狀態(tài),默認為false refunded :退款狀態(tài),默認為false time_paid :付款時間 time_refunded:退款時間 charge_no:返回的charge編號 transaction_no :交易號
步驟:
1.本地創(chuàng)建一條訂單記錄
def create_order
#獲取參數(shù)
#判斷參數(shù)合法性
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.執(zhí)行支付
現(xiàn)在ping++ 平臺創(chuàng)建一條記錄
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"]
#不同支付渠道的回調(diào)地址
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++平臺創(chuàng)建訂單失敗'
logger.error error.http_body
return false
end
end
2.調(diào)用pay_url方法創(chuàng)建訂單,返回給客戶端charge對象,客戶端拿著charge對象去ping++ 平臺支付
def confirm_and_payment
order_no = params[:order_no]
channel = params[:channel]
if order_no.blank? || channel.blank?
render_failure("參數(shù)不完整!") 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
異步通知更新付款結(jié)果
def notify
status = 400
#判斷請求是否有ping++的簽名信息
if request.headers['x-pingplusplus-signature'].blank?
status = 401
logger.debug '【報哪家】:======付款回調(diào)請求來源錯誤?。。。?!'
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)
#處理接收的結(jié)果
event = JSON.parse(raw_data)
#付款成功
if event["type"] == 'charge.succeeded'
# 開發(fā)者在此處加入對支付異步通知的處理代碼
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 '數(shù)據(jù)庫沒有該條記錄!'
end
#退款成功
elsif event['type'] == 'refund.succeeded'
# 開發(fā)者在此處加入對退款異步通知的處理代碼
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 '數(shù)據(jù)庫沒有該條記錄!'
end
else
logger.debug '付款回調(diào)返回未知操作!'
end
else
logger.debug '付款回調(diào)請求來源錯誤!'
status = 403
end
render :nothing => true, :status => status
end

