Ruby on rails realizes payment on Ping + + platform

Time:2022-1-29

Create an order table from the local database.

It is recommended to include the following fields. Refer to the official API( https://pingxx.com/document/api#api -c-new):

order_no:required

?
1
2
3
4
5
6
7
8
9
10
The merchant order number, which adapts 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 digits,
Upacp: 8-40 bits,
yeepay_ WAP: 1-50 bits,
jdpay_ WAP: 1-30 bits,
cnp_ u: 8-20 digits,
cnp_ f: 8-20 digits,
It is recommended to use 8-20 digits. Numbers or letters are required. Special characters are not allowed

app[id]:required

?
1
Please log in to the management platform to view the ID of the app object used for payment.

subject:required

?
1
2
The title of the item. The maximum length of this parameter is 32 Unicode characters,
UnionPay Omni channel (upacp / upacp_wap) is limited to 32 bytes.

body:required

?
1
2
Description information of the product. The maximum length of this parameter is 128 Unicode characters,
yeepay_ WAP is limited to 100 Unicode characters for this parameter.

channel:required

?
1
2
3
4
5
6
7
8
9
10
11
12
Third party payment channels used for payment (please refer to API for more information)
 Alipay: Alipay mobile phone payment
 alipay_ Wap: Alipay mobile phone web payment
 alipay_ Qr: Alipay sweep code payment
 alipay_ pc_ Direct: Alipay PC web payment
 apple_pay:Apple Pay
 BFB: Baidu wallet mobile express payment
 bfb_ WAP: Baidu wallet mobile web payment
 Wx: wechat payment
 wx_ Pub: wechat public account payment
 wx_ pub_ QR: wechat public account code scanning payment
 jdpay_ WAP: JD mobile web payment

amount: required

?
1
2
The total amount of the order. The unit is the minimum currency unit of the corresponding currency,
For example: RMB is cents (if the total amount of the order is 1 yuan, please fill in 100 here).

client_ip: required

?
1
The IP address of the terminal initiating the payment request, in the format of IPv4, such as 127.0.0.1.

      
The above parameters are required when creating an order on the Ping + + platform

The following are the parameters for successful order creation and payment callback on Ping + + platform

?
1
2
3
4
5
6
Pay: payment status, which is false by default
Refunded: refund status, which is false by default
time_ Pay: payment time
time_ Refunded: refund time
charge_ No: returned charge number
transaction_ No: transaction number

Steps:

1. Create an order record locally

 def create_order

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#Get parameters
#Judge the validity of parameters
 
order = Order.new
#Save the order information and pay attention to the length of subject and body
#Generate order number and save
order_no = (Time.now.to_formatted_s(:number)).to_s
6.times{ order_no<<rand(10).to_s }
order.order_no = order_no
 
#Get IP and save
order.client_ip = request.remote_ip
 
if order.save
 #Return success information
else
 render_failure(order.errors.messages.first[1][0])
end
end

2. Execution of payment

Now Ping + + platform creates a record
1. In order Create a new method in Rb file

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 of different payment channels
 case self.channel
   when "alipay"
   extra = {
  }
   when "wx"
   extra = {
  }
  end
 #Ping + + platform creates 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. Call pay_ The URL method creates an order and returns it to the client charge object. The client takes the charge object to Ping + + platform for payment

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def confirm_and_payment
 order_no = params[:order_no]
 channel = params[:channel]
 if order_no.blank? || channel.blank?
  render_failure("Incomplete parameters!") 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

Update payment results asynchronously

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def notify
 
 status = 400
 
 #Judge whether the request has the signature information of Ping + +
 if request.headers['x-pingplusplus-signature'].blank?
  status = 401
  logger.debug '[to whom]: = = = = = 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 verification Ping + + public key"
 pub_key_path ="#{Rails.root}/config/rsa_public_key.pem"
 if verify_signature(raw_data, signature, pub_key_path)
   #Process received results
   event = JSON.parse(raw_data)
   #Payment succeeded
   if event["type"] == 'charge.succeeded'
 
   #Developers add the processing code for asynchronous payment notification 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.save
      status = 200
    else
     status = 500
    end
   else
     logger.debug 'There is no such record in the database! '
   end
 
   #Refund successful
  elsif event['type'] == 'refund.succeeded'
 
    #Developers add the processing code of asynchronous refund notification 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 'There is no such record in the database! '
   end
 
  else
   logger.debug 'unknown operation returned from payment callback!'
  end
 
  else
   logger.debug 'payment callback request source error!'
   status = 403
  end
  render :nothing => true, :status => status
end