Xây dựng thanh toán trực tuyến sử dụng bên thứ 3 - PayPal
Bài đăng này đã không được cập nhật trong 3 năm
Xu hướng sử dụng phương thức thanh toán trực tuyến không còn xa lạ với khá nhiều người, nó đang trở thành xu thế vì thói lười ra khỏi nhà. Vậy để xây dựng 1 phương thức thanh toán như thế trong website của chính mình thì ntn. Mình xin hướng dẫn các bạn sử dụng thanh toán qua 1 bên thứ 3 PAYPAL
Trước hết bạn phải tạo 1 tài khoản tại đây:
- Chúng ta tạo thêm 1 vài tài khoản để test, k giới hạn số lượng
Giờ thì bem thôi Mình sẽ tạo ra 1 model payment để lưu lại cũng như gửi value để thanh toán
Trong controller payments
def new
@payment = Payment.new
end
def create
@payment = Payment.new payment_params
if @payment.save
redirect_to @payment.paypal_url(payment_path(@payment))
else
render :new
end
end
Models payments
def paypal_url return_path
values = {
business: ENV["facilitator_paypal"],
return: "#{Rails.application.secrets.app_host}#{return_path}",
notify_url: "#{Rails.application.secrets.app_host}/update",
invoice: id,
cmd: "_xclick",
amount: amount,
}
"#{Rails.application.secrets.paypal_host}/cgi-bin/webscr?" +
values.to_query
end
Chúng ta có thẻ quản lý các parameter từ file config/secrets.yml
development:
paypal_host: https://www.sandbox.paypal.com
app_host: http://our_ngrok_url
production:
paypal_host: https://www.paypal.com
app_host:
Mình sẽ tạo mới 1 payments khi người dùng thanh toán
Giải thích 1 chút:
-
paypal_url sẽ tương ứng cho đường dẫn thanh toán
-
business: email của tài khoản nhận thanh toán trên paypal do trang web bạn quản lý.
-
cmd: lệnh giao dịch, 1 sản phầm là "_xclick", nếu giao dịch 1 lúc nhiều sản phẩn thì là "_xcartart"
-
return: link đường dẫn sau khi người dùng thanh toán thành công, thường là 1 trang web hiển thị trạng thái thanh toán ở web người bán
-
invoice: id của bản ghi registration để hệ thống cập nhật sau khi Paypal callback
-
amount: khoản tiền cần thanh toán
-
notify_url: link mà paypal sẽ callback lại server bạn sau khi xác minh 1 giao dịch thành công (thường là địa chỉ link trang web của bạn) Lưu ý các địa chỉ nên được lưu vào trong setting
Tiếp đó mình sẽ viết hàm xử lý việc thông tin được gửi trả lại website của chính mình thông qua paypal
...
def show
@payment = Payment.find_by id: params[:id]
if @payment.nil?
redirect_to root_path
end
end
def update
params.permit!
status = params[:payment_status]
if status == "Completed"
@payment = Payment.find params[:invoice]
@payment.update_attributes status: status,
transaction_id: params[:txn_id], purchased_at: Time.now
end
end
Ở đây mình sẽ xử lý khi params được paypal trả về, mình sẽ return ra trang show payments và đồng thời sẽ được update trong database, mình cần thêm 1 vài thứ trong controllers payment để giúp việc đó được thực hiện hiệu quả
#controllers payments
...
before_action :update, only: :show
protect_from_forgery except: [:update]
Giải thích chút về việc phải sự dụng protect_from_forgery
Các bạn có thể nhận thấy hàm protect_from_forgery được khai báo ngay trong Application_controllers trong mỗi app của rails, nó sẽ kiểm tra xem authenticity_token của được trả về có giống nhau k, nhằm mục đích kiểm tra quyền chứng thực của người dùng - CSRF.
Các bạn có thể thấy logic của việc thanh toán qua paypal khi gửi dữ liệu từ paypal return về web của mình đã chắc chắn sẽ vi phạm vào CSRF nên khi giao dịch thành công, paypal trả về sẽ đương nhiên gặp lỗi, chính vì thế chúng ta cần except protect_from_forgery cho hàm update.
Test thử thôi. Đầu tiên là tạo 1 payment thanh toán mới
Sau khi submit from, app sẽ được redirect_to theo link "https://www.sandbox.paypal.com/cgi-bin/webscr?amount=96&business=vuhuutuan262-buyer-1%40gmail.com&cmd=_xclick&invoice=4¬ify_url=http%3A%2F%2Flocalhost%3A3000%2Fupdate&return=http%3A%2F%2Flocalhost%3A3000%2Fpayments%2F4"
(đây là giá trị lấy được thông qua hàm paypal_url)
Chưa đăng nhập
Đã đăng nhập
Thanh toán
Trả về app của mình
Dữ liệu được trả về app gồm
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
mc_gross: '96.00'
invoice: '8'
protection_eligibility: Eligible
address_status: confirmed
payer_id: 68TYR598PYH3U
tax: '0.00'
address_street: 1 Main St
payment_date: 22:56:45 Nov 26, 2016 PST
payment_status: Completed
charset: windows-1252
address_zip: '95131'
first_name: test
mc_fee: '3.08'
address_country_code: US
address_name: test facilitator's Test Store
notify_version: '3.8'
custom: ''
payer_status: verified
business: vuhuutuan262-buyer-1@gmail.com
address_country: United States
address_city: San Jose
quantity: '1'
payer_email: vuhuutuan262-facilitator@gmail.com
verify_sign: AFcWxV21C7fd0v3bYYYRCpSSRl31ADolIEn2MVG3v7UrPgfJ2yPyX8F0
txn_id: 6G165125E3453420G
payment_type: instant
payer_business_name: test facilitator's Test Store
last_name: facilitator
address_state: CA
receiver_email: vuhuutuan262-buyer-1@gmail.com
payment_fee: '3.08'
receiver_id: FP6NY45MZGERA
txn_type: web_accept
item_name: ''
mc_currency: USD
item_number: ''
residence_country: US
test_ipn: '1'
handling_amount: '0.00'
transaction_subject: ''
payment_gross: '96.00'
shipping: '0.00'
auth: AZ9ZrcSDQyqqJwDhbez20ZlJ4382mcsm1oHVQenuGImD89KuUSj93bXeynn7o7OlzJ7sf-yRLsfTTpI3XLhMmqA
controller: payments
action: show
id: '8'
Chúng ta sẽ chọn lọc dữ liệu mình cần để lửu vào database, như trên thì mình sẽ lưu lại
- status: Chỉ khi vào giao dịch thành công thì paypal mới trả về Complete, các bạn nên chú ý điều đó
- transaction_id: id của giao dịch, với mỗi giao dịch đều sinh ra 1 transaction_id nên bạn có thể vào account của mình và tra lại được giao dịch đó, rất là tiện
- purchased_at: mình cần lưu lại thời gian của việc thanh toán trong database của mình cho dễ quản lý
Như vâỵ là đã xây dựng thành công thanh toán qua bên thứ 3, và còn 1 chút chú ý cho các bạn có thể tùy chỉnh với website của mình:
- Với những khách hàng muốn thanh toán nhiều sản phẩm một lúc
#model payment
line_items.each_with_index do |item, index|
values.merge!({
"amount_#{index + 1}" => item.unit_price,
"item_name_#{index + 1}" => item.name,
"item_number_#{index + 1}" => item.identifier,
"quantity_#{index + 1}" => item.quantity
})
end
- Lưu ý bạn nếu trong trường hợp người dùng thanh toán thành công nhưng k return lại website thì payments đấy sẽ k được cập nhật trong database của mình, khi đó bạn có thể update status của payment ngat khi người dùng submit form payment để có thể tiện việc check lại giao dịch.
Hy vọng bài viết sẽ giúp ích được các bạn!!
All rights reserved