คุณลักษณะสำคัญสำหรับ บริษัท อีคอมเมิร์ซขนาดใหญ่เช่น AliExpress, Ebay และ Amazon คือวิธีจัดการการชำระเงินที่ปลอดภัยซึ่งเป็นสิ่งจำเป็นสำหรับธุรกิจของพวกเขา หากคุณสมบัตินี้ล้มเหลวผลที่ตามมาจะร้ายแรง สิ่งนี้ใช้กับผู้นำในอุตสาหกรรมและ นักพัฒนา Ruby on Rails ทำงานบนแอพอีคอมเมิร์ซ
การรักษาความปลอดภัยทางไซเบอร์เป็นสิ่งสำคัญในการป้องกันการโจมตีและวิธีที่จะทำให้กระบวนการทำธุรกรรมปลอดภัยยิ่งขึ้นคือการขอให้บริการของบุคคลที่สามจัดการ การรวมเกตเวย์การชำระเงินไว้ในแอปพลิเคชันของคุณเป็นวิธีที่จะบรรลุเป้าหมายนี้เนื่องจากมีการอนุญาตผู้ใช้การเข้ารหัสข้อมูลและแดชบอร์ดเพื่อให้คุณสามารถติดตามสถานะการทำธุรกรรมได้ทันที
มีบริการเกตเวย์การชำระเงินที่หลากหลายบนเว็บ แต่ในบทความนี้ฉันจะเน้นไปที่การบูรณาการ ลาย และ PayPal ไปยังแอปพลิเคชัน Rails หากต้องการพูดถึงคนอื่น ๆ : Amazon Payments, Square, SecurePay, WorldPay, Authorize.Net, 2Checkout.com, Braintree, Amazon หรือ BlueSnap
โดยทั่วไปจะมีแบบฟอร์ม / ปุ่มในแอปพลิเคชันของคุณซึ่งผู้ใช้สามารถเข้าสู่ระบบ / ใส่ข้อมูลบัตรเครดิตได้ PayPal และ Stripe ทำให้ขั้นตอนแรกนี้ปลอดภัยยิ่งขึ้นโดยใช้ iframe
แบบฟอร์มหรือ popups
ซึ่งป้องกันไม่ให้แอปพลิเคชันของคุณจัดเก็บข้อมูลบัตรเครดิตของผู้ใช้ที่ละเอียดอ่อนเนื่องจากจะส่งคืนโทเค็นที่แสดงธุรกรรมนี้ ผู้ใช้บางรายอาจรู้สึกมั่นใจมากขึ้นในการดำเนินการชำระเงินโดยทราบว่าบริการของบุคคลที่สามกำลังจัดการขั้นตอนการทำธุรกรรมดังนั้นนี่อาจเป็นสิ่งดึงดูดสำหรับใบสมัครของคุณ
หลังจากตรวจสอบสิทธิ์ข้อมูลผู้ใช้แล้วเกตเวย์การชำระเงินจะยืนยันการชำระเงินโดยติดต่อผู้ประมวลผลการชำระเงินซึ่งติดต่อกับธนาคารเพื่อชำระเงิน เพื่อให้แน่ใจว่าธุรกรรมถูกหัก / เครดิตอย่างถูกต้อง
Stripe ใช้แบบฟอร์มบัตรเครดิตที่ถามหมายเลขบัตรเครดิตประวัติย่อและวันหมดอายุ ดังนั้นผู้ใช้จะต้องกรอกข้อมูลบัตรเครดิตในอินพุต Stripe ที่ปลอดภัย หลังจากให้ข้อมูลนี้แล้วแอปพลิเคชันของคุณจะประมวลผลการชำระเงินนี้ผ่านโทเค็น
ไม่เหมือน Stripe ตรงที่ PayPal เปลี่ยนเส้นทางผู้ใช้ไปยังหน้าเข้าสู่ระบบ PayPal ผู้ใช้อนุญาตและเลือกวิธีการชำระเงินผ่าน PayPal และอีกครั้งส่วนหลังของคุณจะจัดการโทเค็นแทนข้อมูลที่ละเอียดอ่อนของผู้ใช้
สิ่งสำคัญคือต้องระบุว่าสำหรับเกตเวย์การชำระเงินทั้งสองนี้ส่วนหลังของคุณควรขอให้ดำเนินการทำธุรกรรมผ่าน Stripe หรือ PayPal API ซึ่งจะตอบตกลง / NOK ดังนั้นแอปพลิเคชันของคุณควรเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าสำเร็จหรือหน้าข้อผิดพลาดตามนั้น
วัตถุประสงค์ของบทความนี้คือเพื่อให้คำแนะนำโดยย่อสำหรับการรวมเกตเวย์การชำระเงินทั้งสองนี้ไว้ในแอปพลิเคชันเดียว สำหรับการทดสอบทั้งหมดเราจะใช้แซนด์บ็อกซ์และบัญชีทดสอบที่ Stripe และ PayPal จัดหาให้เพื่อจำลองการชำระเงิน
ก่อนที่จะรวมเกตเวย์การชำระเงินเราจะทำการตั้งค่าสำหรับการเริ่มต้นแอปพลิเคชันโดยการเพิ่มอัญมณีตารางฐานข้อมูลและหน้าดัชนี โครงการนี้สร้างขึ้นโดยใช้ Rails เวอร์ชัน 5.2.3 และ Ruby 2.6.3
บันทึก: คุณสามารถตรวจสอบใหม่ คุณลักษณะ Rails 6 ในบทความล่าสุดของเรา .
ขั้นตอนที่ 1: เริ่มต้นแอปพลิเคชัน Rails
เริ่มต้นโครงการโดยการรันการเริ่มต้นโครงการด้วย rails
คำสั่งด้วยชื่อแอปของคุณ:
rails new YOUR_APP_NAME
และ cd
ในโฟลเดอร์แอปพลิเคชันของคุณ
ขั้นตอนที่ 2: ติดตั้งอัญมณี
นอกจากอัญมณี Stripe และ PayPal แล้วยังมีการเพิ่มอัญมณีอื่น ๆ อีกเล็กน้อย:
devise
: ใช้สำหรับการตรวจสอบผู้ใช้และการอนุญาตhaml
: เครื่องมือสร้างเทมเพลตสำหรับการแสดงผลหน้าผู้ใช้jquery-rails
: สำหรับ jquery
ในสคริปต์ส่วนหน้าmoney-rails
: สำหรับการแสดงค่าเงินที่จัดรูปแบบเพิ่มใน Gemfile
:
gem 'devise', '>= 4.7.1' gem 'haml' gem 'jquery-rails' gem 'money-rails'
หลังจากเพิ่มแล้วให้รันใน CLI ของคุณ:
bundle install
ขั้นตอนที่ 3: เริ่มต้นอัญมณี
อัญมณีเหล่านี้บางส่วนจะต้องมีการเริ่มต้นนอกเหนือจากการติดตั้งผ่าน bundle
การติดตั้งอุปกรณ์:
rails g devise:install
การเริ่มต้น money-rails
:
rails g money_rails:initializer
เริ่มต้น jquery-rails
โดยต่อท้าย app/assets/javascripts/application.js
ดังต่อไปนี้:
//= require jquery //= require jquery_ujs
ขั้นตอนที่ 4: ตารางและการโยกย้าย
สามตารางจะถูกใช้ในโครงการนี้ ผู้ใช้ , ผลิตภัณฑ์ และ คำสั่งซื้อ .
Users
: จะถูกสร้างขึ้นโดยการประดิษฐ์Products
คอลัมน์:name
price_cents
Stripe_plan_name
: ID ที่แสดงแผนการสมัครสมาชิกที่สร้างขึ้นใน Stripe เพื่อให้ผู้ใช้สมัครสมาชิกได้ ฟิลด์นี้จำเป็นสำหรับผลิตภัณฑ์ที่เกี่ยวข้องกับแผน Stripe เท่านั้นpaypal_plan_name
: เหมือนกับ stripe_plan_name
แต่สำหรับ PayPalOrders
คอลัมน์:product_id
user_id
status
: สิ่งนี้จะแจ้งให้ทราบว่าคำสั่งซื้ออยู่ระหว่างดำเนินการล้มเหลวหรือชำระเงินtoken
: นี่คือโทเค็นที่สร้างขึ้นจาก API (ไม่ว่าจะเป็น Stripe หรือ PayPal) เพื่อเริ่มต้นธุรกรรมprice_cents
: คล้ายกับผลิตภัณฑ์ แต่ใช้เพื่อทำให้ค่านี้คงอยู่ในบันทึกคำสั่งซื้อpayment_gateway
: ร้านค้าที่ใช้เกตเวย์การชำระเงินสำหรับการสั่งซื้อ PayPal หรือ Stripecustomer_id
: จะใช้สำหรับ Stripe เพื่อจัดเก็บลูกค้า Stripe สำหรับการสมัครสมาชิกและจะมีการอธิบายรายละเอียดเพิ่มเติมในส่วนต่อไปในการสร้างตารางเหล่านี้ต้องมีการสร้างการย้ายข้อมูลเล็กน้อย:
สำหรับการสร้างไฟล์ ตารางผู้ใช้ . วิ่ง:
rails g devise User
สำหรับการสร้างไฟล์ ตารางผลิตภัณฑ์ . สร้างการย้ายข้อมูลโดยเรียกใช้:
rails generate migration CreateProducts name:string stripe_plan_name:string paypal_plan_name:string
เปิดไฟล์การย้ายข้อมูลที่คุณสร้างขึ้นซึ่งควรอยู่ที่ db/migrate/
และทำการเปลี่ยนแปลงเพื่อให้การย้ายข้อมูลของคุณมีลักษณะคล้ายกับสิ่งนี้:
class CreateProducts สำหรับการสร้างไฟล์ ตารางคำสั่งซื้อ . สร้างการย้ายข้อมูลโดยเรียกใช้:
rails generate migration CreateOrders product_id:integer user_id:integer status:integer token:string charge_id:string error_message:string customer_id:string payment_gateway:integer
อีกครั้งเปิดไฟล์การย้ายข้อมูลที่คุณสร้างขึ้นซึ่งควรอยู่ที่ db/migrate/
และทำการเปลี่ยนแปลงไฟล์นั้นเพื่อให้มีลักษณะคล้ายกับสิ่งนี้:
class CreateOrders เรียกใช้การย้ายฐานข้อมูลโดยดำเนินการ:
rails db:migrate
ขั้นตอนที่ 5: สร้างแบบจำลอง
โมเดลผู้ใช้ถูกสร้างขึ้นแล้วจากการติดตั้งอุปกรณ์และไม่จำเป็นต้องมีการเปลี่ยนแปลงใด ๆ นอกจากนั้นจะมีการสร้างโมเดลสองรุ่นสำหรับ สินค้า และ ใบสั่ง .
สินค้า. เพิ่มไฟล์ใหม่ app/models/product.rb
ด้วย:
class Product ใบสั่ง. เพิ่มไฟล์ใหม่ app/models/order.rb
ด้วย:
class Order { where(created_at: 1.minutes.ago..DateTime.now) } def set_paid self.status = Order.statuses[:paid] end def set_failed self.status = Order.statuses[:failed] end def set_paypal_executed self.status = Order.statuses[:paypal_executed] end end
ขั้นตอนที่ 6: เติมฐานข้อมูล
ผู้ใช้และผลิตภัณฑ์สองรายการจะถูกสร้างขึ้นในคอนโซล บันทึกการสั่งซื้อจะถูกสร้างขึ้นตามการทดสอบการชำระเงิน
- เรียกใช้
rails s
- ในเบราว์เซอร์ของคุณไปที่
http://localhost:3000
- คุณจะถูกเปลี่ยนเส้นทางไปยังหน้าลงชื่อสมัครใช้
- ลงทะเบียนผู้ใช้โดยกรอกที่อยู่อีเมลและรหัสผ่าน
- ในเทอร์มินัลของคุณบันทึกต่อไปนี้จะถูกแจ้งว่ามีการสร้างผู้ใช้ในฐานข้อมูลของคุณ:
User Create (0.1ms) INSERT INTO 'users' ('email', 'encrypted_password', 'created_at', 'updated_at') VALUES (?, ?, ?, ?) …
- สร้างผลิตภัณฑ์สองรายการโดยไม่ต้องสมัครสมาชิกโดยเรียกใช้
rails c
และเพิ่ม: Product.create(name: 'Awesome T-Shirt', price_cents: 3000)
Product.create(name: 'Awesome Sneakers', price_cents: 5000)
ขั้นตอนที่ 7: สร้างหน้าดัชนี
หน้าหลักสำหรับโครงการประกอบด้วยการเลือกผลิตภัณฑ์สำหรับการซื้อหรือการสมัครสมาชิก นอกจากนี้ยังมีส่วนสำหรับการเลือกวิธีการชำระเงิน (Stripe หรือ PayPal) นอกจากนี้ยังใช้ปุ่มส่งสำหรับเกตเวย์การชำระเงินแต่ละประเภทสำหรับ PayPal เราจะเพิ่มการออกแบบปุ่มของตัวเองผ่านไลบรารี JavaScript
ขั้นแรกสร้างเส้นทางสำหรับ index
และ submit
ใน config/routes.rb
.
Rails.application.routes.draw do devise_for :users get '/', to: 'orders#index' post '/orders/submit', to: 'orders#submit' end
สร้างและเพิ่มการดำเนินการ index
และ submit
ในตัวควบคุมคำสั่งซื้อ app/controllers/orders_controller.rb
. orders#index
การดำเนินการเก็บสองตัวแปรที่จะใช้ในส่วนหน้า: @products_purchase
ซึ่งมีรายการผลิตภัณฑ์ที่ไม่มีแผนและ @products_subscription
ซึ่งมีผลิตภัณฑ์ที่มีทั้งแผน PayPal และ Stripe
class OrdersController สร้างไฟล์ใน app/views/orders/index.html.haml
. ไฟล์นี้มีอินพุตทั้งหมดที่เราจะส่งไปยังส่วนหลังของเราผ่านวิธีการส่งและการโต้ตอบสำหรับเกตเวย์การชำระเงินและการเลือกผลิตภัณฑ์ แอตทริบิวต์ชื่ออินพุตบางส่วนมีดังนี้:
Orders[product_id]
จัดเก็บรหัสผลิตภัณฑ์ Orders[payment_gateway]
มีช่องทางการชำระเงินที่มีค่า Stripe หรือ PayPal สำหรับอีกช่องทางหนึ่ง
%div %h1 List of products = form_tag({:controller => 'orders', :action => 'submit' }, {:id => 'order-details'}) do %input{id:'order-type', :type=>'hidden', :value=>'stripe', :name=>'orders[payment_gateway]'} .form_row %h4 Charges/Payments - @products_purchase.each do |product| %div{'data-charges-and-payments-section': true} = radio_button_tag 'orders[product_id]', product.id, @products_purchase.first == product %span{id: 'radioButtonName#{product.id}'} #{product.name} %span{id: 'radioButtonPrice#{product.id}', :'data-price' => '#{product.price_cents}'} #{humanized_money_with_symbol product.price} %br %h4 Subscriptions - @products_subscription.each do |product| %div = radio_button_tag 'orders[product_id]', product.id, false %span{id: 'radioButtonName#{product.id}'} #{product.name} %span{id: 'radioButtonPrice#{product.id}', :'data-price' => '#{product.price_cents}'} #{humanized_money_with_symbol product.price} %br %hr %h1 Payment Method .form_row %div = radio_button_tag 'payment-selection', 'stripe', true, onclick: 'changeTab();' %span Stripe %br %div = radio_button_tag 'payment-selection', 'paypal', false, onclick: 'changeTab();' %span Paypal %br %br %div{id:'tab-stripe', class:'paymentSelectionTab active'} %div{id:'card-element'} %div{id:'card-errors', role:'alert'} %br %br = submit_tag 'Buy it!', id: 'submit-stripe' %div{id:'tab-paypal', class:'paymentSelectionTab'} %div{id: 'submit-paypal'} %br %br %hr :javascript function changeTab() { var newActiveTabID = $('input[name='payment-selection']:checked').val(); $('.paymentSelectionTab').removeClass('active'); $('#tab-' + newActiveTabID).addClass('active'); } :css #card-element { width:500px; } .paymentSelectionTab { display: none; } .paymentSelectionTab.active { display: block !important; }
หากคุณเรียกใช้แอปพลิเคชันของคุณด้วย rails s
และเยี่ยมชมเพจของคุณใน http://localhost:3000
. คุณควรจะเห็นหน้าดังต่อไปนี้:
หน้าดัชนีดิบที่ไม่มีการรวม Stripe และ PayPal ที่เก็บข้อมูลรับรองเกตเวย์การชำระเงิน
คีย์ PayPal และ Stripe จะถูกเก็บไว้ในไฟล์ที่ Git ไม่ติดตาม มีคีย์สองประเภทที่เก็บไว้ในไฟล์นี้สำหรับเกตเวย์การชำระเงินแต่ละอันและสำหรับตอนนี้เราจะใช้ค่าดัมมี่สำหรับคีย์เหล่านี้ คำแนะนำเพิ่มเติมสำหรับการสร้างคีย์เหล่านี้แสดงไว้ในส่วนต่อไป
ขั้นตอนที่ 1: เพิ่มสิ่งนี้ใน .gitignore
.
/config/application.yml
ขั้นตอนที่ 2: สร้างไฟล์ด้วยข้อมูลรับรองของคุณใน config/application.yml
ควรมี PayPal และ Stripe sandbox / คีย์ทดสอบทั้งหมดสำหรับการเข้าถึง API เหล่านี้
test: &default PAYPAL_ENV: sandbox PAYPAL_CLIENT_ID: YOUR_CREDENTIAL_HERE PAYPAL_CLIENT_SECRET: YOUR_CREDENTIAL_HERE STRIPE_PUBLISHABLE_KEY: YOUR_CREDENTIAL_HERE STRIPE_SECRET_KEY: YOUR_CREDENTIAL_HERE development: <<: *default
ขั้นตอนที่ 3: เพื่อเก็บตัวแปรจากไฟล์ config/application.yml
เมื่อแอปพลิเคชันเริ่มต้นให้เพิ่มบรรทัดเหล่านี้ใน config/application.rb
ภายใน Application
คลาสจึงจะพร้อมใช้งานใน ENV
config_file = Rails.application.config_for(:application) config_file.each do |key,value| ENV[key] = value end unless config_file.nil?
การกำหนดค่า Stripe
เราจะเพิ่มอัญมณีสำหรับการใช้ Stripe API: stripe-rails
จำเป็นต้องสร้างบัญชี Stripe เพื่อให้สามารถดำเนินการเรียกเก็บเงินและการสมัครสมาชิกได้ หากต้องการคุณสามารถดูวิธีการ API สำหรับ Stripe API ได้ในไฟล์ เอกสารอย่างเป็นทางการ .
ขั้นตอนที่ 1: เพิ่มแถบรางอัญมณีลงในโครงการของคุณ
แถบรางอัญมณี จะจัดเตรียมอินเทอร์เฟซสำหรับคำขอ API ทั้งหมดที่ใช้ในโครงการนี้
เพิ่มสิ่งนี้ใน Gemfile
:
gem 'stripe-rails'
วิ่ง:
bundle install
ขั้นตอนที่ 2: สร้างคีย์ API ของคุณ
ในการมีคีย์ API สำหรับสื่อสารกับ Stripe คุณจะต้องสร้างบัญชีใน Stripe ในการทดสอบแอปพลิเคชันคุณสามารถใช้โหมดการทดสอบได้ดังนั้นจึงไม่จำเป็นต้องกรอกข้อมูลธุรกิจจริงในขั้นตอนการสร้างบัญชี Stripe
- สร้างบัญชีใน Stripe หากคุณไม่มี ( https://dashboard.stripe.com/ ).
- ในขณะที่ยังอยู่ในแผงควบคุม Stripe หลังจากเข้าสู่ระบบแล้วให้สลับ ดูข้อมูลการทดสอบ บน.
- ที่ https://dashboard.stripe.com/test/apikeys แทนที่
YOUR_CREDENTIAL_HERE
สำหรับค่า STRIPE_PUBLISHABLE_KEY
และ STRIPE_SECRET_KEY
ใน /config/application.yml
ด้วยเนื้อหาจาก Publishable Key
และ Secret key
.
ขั้นตอนที่ 3: เริ่มต้นโมดูล Stripe
นอกเหนือจากการเปลี่ยนคีย์แล้วเรายังต้องเริ่มต้นโมดูล Stripe เพื่อให้ใช้คีย์ที่ตั้งค่าไว้แล้วใน ENV
สร้างไฟล์ใน config/initializers/stripe.rb
กับ:
Rails.application.configure do config.stripe.secret_key = ENV['STRIPE_SECRET_KEY'] config.stripe.publishable_key = ENV['STRIPE_PUBLISHABLE_KEY'] end
ขั้นตอนที่ 4: รวม Stripe ไว้ที่ส่วนหน้า
เราจะเพิ่มไลบรารี Stripe JavaScript และตรรกะในการส่งโทเค็นซึ่งแสดงถึงข้อมูลบัตรเครดิตของผู้ใช้และจะถูกประมวลผลในส่วนหลังของเรา
ใน index.html.haml
เพิ่มไฟล์นี้ไว้ที่ด้านบนสุดของไฟล์ การดำเนินการนี้จะใช้โมดูล Stripe (ให้มาโดย gem) เพื่อเพิ่มไลบรารี Stripe javascript ในหน้าของผู้ใช้
= stripe_javascript_tag
Stripe ใช้ช่องป้อนข้อมูลที่ปลอดภัยซึ่งสร้างขึ้นผ่าน API ตามที่สร้างขึ้นใน iframe
สร้างผ่าน API นี้คุณจะไม่ต้องกังวลเกี่ยวกับช่องโหว่ที่อาจเกิดขึ้นในการจัดการข้อมูลบัตรเครดิตของผู้ใช้ นอกจากนี้ส่วนหลังของคุณจะไม่สามารถประมวลผล / จัดเก็บข้อมูลที่ละเอียดอ่อนของผู้ใช้และจะได้รับโทเค็นที่แสดงถึงข้อมูลนี้เท่านั้น
ช่องป้อนข้อมูลเหล่านี้สร้างขึ้นโดยการเรียก stripe.elements().create('card')
หลังจากนั้นจำเป็นต้องเรียกวัตถุที่ส่งคืนด้วย mount()
โดยการส่งผ่านเป็นอาร์กิวเมนต์ id / class ขององค์ประกอบ HTML ที่ควรติดตั้งอินพุตเหล่านี้ สามารถดูข้อมูลเพิ่มเติมได้ที่ ลาย .
เมื่อผู้ใช้กดปุ่มส่งด้วยวิธีการชำระเงิน Stripe การเรียก API อื่นที่ส่งคืนสัญญาจะดำเนินการกับองค์ประกอบการ์ด Stripe ที่สร้างขึ้น:
stripe.createToken(card).then(function(result)
result
ตัวแปรของฟังก์ชั่นนี้หากไม่มีการกำหนดข้อผิดพลาดคุณสมบัติจะมีโทเค็นซึ่งสามารถเรียกค้นได้โดยการเข้าถึงแอตทริบิวต์ result.token.id
โทเค็นนี้จะถูกส่งไปที่ส่วนหลัง
ในการทำการเปลี่ยนแปลงเหล่านี้ให้แทนที่โค้ดที่แสดงความคิดเห็น // YOUR STRIPE AND PAYPAL CODE WILL BE HERE
ใน index.html.haml
กับ:
(function setupStripe() { //Initialize stripe with publishable key var stripe = Stripe('#{ENV['STRIPE_PUBLISHABLE_KEY']}'); //Create Stripe credit card elements. var elements = stripe.elements(); var card = elements.create('card'); //Add a listener in order to check if card.addEventListener('change', function(event) { //the div card-errors contains error details if any var displayError = document.getElementById('card-errors'); document.getElementById('submit-stripe').disabled = false; if (event.error) { // Display error displayError.textContent = event.error.message; } else { // Clear error displayError.textContent = ''; } }); // Mount Stripe card element in the #card-element div. card.mount('#card-element'); var form = document.getElementById('order-details'); // This will be called when the #submit-stripe button is clicked by the user. form.addEventListener('submit', function(event) { $('#submit-stripe').prop('disabled', true); event.preventDefault(); stripe.createToken(card).then(function(result) { if (result.error) { // Inform that there was an error. var errorElement = document.getElementById('card-errors'); errorElement.textContent = result.error.message; } else { // Now we submit the form. We also add a hidden input storing // the token. So our back-end can consume it. var $form = $('#order-details'); // Add a hidden input orders[token] $form.append($('').val(result.token.id)); // Set order type $('#order-type').val('stripe'); $form.submit(); } }); return false; }); }()); //YOUR PAYPAL CODE WILL BE HERE
หากคุณเยี่ยมชมเพจของคุณควรมีลักษณะดังต่อไปนี้พร้อมกับช่องป้อนข้อมูล Stripe secure ใหม่:
หน้าดัชนีรวมกับช่องป้อนข้อมูลที่ปลอดภัยของ Stripe ขั้นตอนที่ 5: ทดสอบแอปพลิเคชันของคุณ
กรอกแบบฟอร์มบัตรเครดิตด้วยบัตรทดสอบ ( https://stripe.com/docs/testing ) และส่งหน้า ตรวจสอบว่า submit
การกระทำถูกเรียกด้วยพารามิเตอร์ทั้งหมด ( product_id , ช่องทางการชำระเงิน และ โทเค็น ) ในเอาต์พุตเซิร์ฟเวอร์ของคุณ
Stripe ค่าธรรมเนียม
ค่าธรรมเนียม Stripe แสดงถึงธุรกรรมครั้งเดียว ดังนั้นหลังจากการทำธุรกรรมการเรียกเก็บเงิน Stripe คุณจะได้รับเงินจากลูกค้าโดยตรง เหมาะอย่างยิ่งสำหรับการขายผลิตภัณฑ์ที่ไม่เกี่ยวข้องกับแผน ในส่วนต่อไปฉันจะแสดงวิธีการทำธุรกรรมประเภทเดียวกันกับ PayPal แต่ชื่อของ PayPal สำหรับธุรกรรมประเภทนี้คือ การชำระเงิน .
ในส่วนนี้ฉันจะจัดเตรียมโครงกระดูกทั้งหมดสำหรับจัดการและส่งคำสั่งซื้อ เราสร้างคำสั่งซื้อใน submit
การดำเนินการเมื่อส่งแบบฟอร์ม Stripe คำสั่งนี้เริ่มแรกจะมี รอดำเนินการ สถานะดังนั้นหากมีสิ่งผิดปกติเกิดขึ้นขณะดำเนินการคำสั่งซื้อนี้คำสั่งซื้อจะยังคงเป็น รอดำเนินการ .
หากข้อผิดพลาดใด ๆ เกิดขึ้นจากการเรียก Stripe API เราจะกำหนดลำดับในรูปแบบ ล้มเหลว สถานะและหากการเรียกเก็บเงินเสร็จสมบูรณ์จะอยู่ในรูปแบบ จ่าย สถานะ. ผู้ใช้จะถูกเปลี่ยนเส้นทางตามการตอบสนองของ Stripe API ดังที่แสดงในกราฟต่อไปนี้:
การทำธุรกรรมแบบ Stripe นอกจากนี้เมื่อดำเนินการเรียกเก็บเงิน Stripe ID จะถูกส่งกลับ เราจะจัดเก็บ ID นี้เพื่อให้คุณสามารถค้นหาได้ในภายหลังในแดชบอร์ด Stripe ของคุณหากจำเป็น นอกจากนี้ยังสามารถใช้รหัสนี้หากต้องคืนเงินคำสั่งซื้อ สิ่งดังกล่าวจะไม่ถูกสำรวจในบทความนี้
ขั้นตอนที่ 1: สร้างบริการ Stripe
เราจะใช้คลาสซิงเกิลเพื่อแสดงการดำเนินการของ Stripe โดยใช้ Stripe API ในการสร้างการเรียกเก็บเงินวิธีการ Stripe::Charge.create
ถูกเรียกและแอตทริบิวต์ ID อ็อบเจ็กต์ที่ส่งคืนจะถูกเก็บไว้ในเรกคอร์ดคำสั่ง charge_id
นี้ create
ฟังก์ชันถูกเรียกโดยการส่งโทเค็นที่มาในส่วนหน้าราคาคำสั่งซื้อและคำอธิบาย
ดังนั้นสร้างโฟลเดอร์ใหม่ app/services/orders
และเพิ่มบริการ Stripe: app/services/orders/stripe.rb
มี Orders::Stripe
คลาส singleton ซึ่งมีรายการในเมธอด execute
.
class Orders::Stripe INVALID_STRIPE_OPERATION = 'Invalid Stripe Operation' def self.execute(order:, user:) product = order.product # Check if the order is a plan if product.stripe_plan_name.blank? charge = self.execute_charge(price_cents: product.price_cents, description: product.name, card_token: order.token) else #SUBSCRIPTIONS WILL BE HANDLED HERE end unless charge&.id.blank? # If there is a charge with id, set order paid. order.charge_id = charge.id order.set_paid end rescue Stripe::StripeError => e # If a Stripe error is raised from the API, # set status failed and an error message order.error_message = INVALID_STRIPE_OPERATION order.set_failed end private def self.execute_charge(price_cents:, description:, card_token:) Stripe::Charge.create({ amount: price_cents.to_s, currency: 'usd', description: description, source: card_token }) end end
ขั้นตอนที่ 2: ใช้การดำเนินการส่งและเรียกใช้บริการ Stripe
ใน orders_controller.rb
ให้เพิ่มสิ่งต่อไปนี้ใน submit
การดำเนินการซึ่งโดยทั่วไปจะเรียกใช้บริการ Orders::Stripe.execute
โปรดทราบว่ามีการเพิ่มฟังก์ชั่นส่วนตัวใหม่สองฟังก์ชัน: prepare_new_order
และ order_params
.
def submit @order = nil #Check which type of order it is if order_params[:payment_gateway] == 'stripe' prepare_new_order Orders::Stripe.execute(order: @order, user: current_user) elsif order_params[:payment_gateway] == 'paypal' #PAYPAL WILL BE HANDLED HERE end ensure if @order&.save if @order.paid? # Success is rendered when order is paid and saved return render html: SUCCESS_MESSAGE elsif @order.failed? && [email protected] _message.blank? # Render error only if order failed and there is an error_message return render html: @order.error_message end end render html: FAILURE_MESSAGE end private # Initialize a new order and and set its user, product and price. def prepare_new_order @order = Order.new(order_params) @order.user_id = current_user.id @product = Product.find(@order.product_id) @order.price_cents = @product.price_cents end def order_params params.require(:orders).permit(:product_id, :token, :payment_gateway, :charge_id) end
ขั้นตอนที่ 3: ทดสอบแอปพลิเคชันของคุณ
ตรวจสอบว่าการดำเนินการส่งเมื่อเรียกด้วยการ์ดทดสอบที่ถูกต้องทำการเปลี่ยนเส้นทางไปยังข้อความสำเร็จหรือไม่ นอกจากนี้ตรวจสอบในไฟล์ แผงหน้าปัดลาย หากมีการแสดงคำสั่งซื้อด้วย
การสมัครสมาชิก Stripe
การสมัครสมาชิกหรือแผนสามารถสร้างขึ้นสำหรับการชำระเงินที่เกิดขึ้นประจำ สำหรับผลิตภัณฑ์ประเภทนี้ผู้ใช้จะถูกเรียกเก็บเงินรายวันรายสัปดาห์รายเดือนหรือรายปีโดยอัตโนมัติตาม การกำหนดค่าแผน . ในส่วนนี้เราจะใช้ฟิลด์สำหรับผลิตภัณฑ์ stripe_plan_name
ในการจัดเก็บ ID แผน - จริงๆแล้วเป็นไปได้ที่เราจะเลือก ID และเราจะเรียกมันว่า premium-plan
- ซึ่งจะใช้เพื่อสร้างความสัมพันธ์ customer subscription
นอกจากนี้เราจะสร้างคอลัมน์ใหม่สำหรับตารางผู้ใช้ที่เรียกว่า stripe_customer_id
ซึ่งจะเต็มไปด้วยคุณสมบัติ id ของอ็อบเจ็กต์ลูกค้า Stripe ลูกค้า Stripe ถูกสร้างขึ้นเมื่อฟังก์ชัน Stripe::Customer.create
ถูกเรียกและคุณยังสามารถตรวจสอบลูกค้าที่สร้างและเชื่อมโยงกับบัญชีของคุณได้ใน ( https://dashboard.stripe.com/test/customers ). ลูกค้าถูกสร้างขึ้นโดยการส่ง source
พารามิเตอร์ซึ่งในกรณีของเราคือโทเค็นที่สร้างขึ้นในส่วนหน้าซึ่งถูกส่งเมื่อส่งแบบฟอร์ม
ออบเจ็กต์ของลูกค้าที่ได้รับจากการเรียก Stripe API ที่กล่าวถึงล่าสุดยังใช้สำหรับการสร้างการสมัครสมาชิกซึ่งทำได้โดยการเรียก customer.subscriptions.create
และส่งรหัสแผนเป็นพารามิเตอร์
นอกจากนี้ stripe-rails
gem มีอินเทอร์เฟซสำหรับดึงข้อมูลและอัปเดตลูกค้าจาก Stripe ซึ่งทำได้โดยการโทร Stripe::Customer.retrieve
และ Stripe::Customer.update
ตามลำดับ
ดังนั้นเมื่อบันทึกผู้ใช้มี stripe_customer_id
แล้วแทนที่จะสร้างลูกค้าใหม่โดยใช้ Stripe::Customer.create
เราจะเรียก Stripe::Customer.retrieve
ผ่าน stripe_customer_id
เป็นพารามิเตอร์ตามด้วย Stripe::Customer.update
และในกรณีนี้ให้ส่งโทเค็นพารามิเตอร์
อันดับแรกเราจะสร้างแผนโดยใช้ Stripe API เพื่อให้เราสามารถสร้างผลิตภัณฑ์สมัครสมาชิกใหม่โดยใช้ฟิลด์ stripe_plan_name
หลังจากนั้นเราจะทำการแก้ไขในส่วน orders_controller
และบริการ Stripe เพื่อให้การสร้างและดำเนินการสมัครสมาชิก Stripe ได้รับการจัดการ
ขั้นตอนที่ 1: สร้างแผนโดยใช้ Stripe API
เปิดคอนโซลของคุณโดยใช้คำสั่ง rails c
สร้างการสมัครสำหรับบัญชี Stripe ของคุณด้วย:
Stripe::Plan.create({ amount: 10000, interval: 'month', product: { name: 'Premium plan', }, currency: 'usd', id: 'premium-plan', })
หากผลลัพธ์ที่ส่งคืนในขั้นตอนนี้เป็นจริงแสดงว่าสร้างแผนสำเร็จแล้วและคุณสามารถเข้าถึงได้ในไฟล์ แผงหน้าปัดลาย .
ขั้นตอนที่ 2: สร้างผลิตภัณฑ์ในฐานข้อมูลด้วย stripe_plan_name
ชุดสนาม
ตอนนี้สร้างผลิตภัณฑ์ด้วย stripe_plan_name
ตั้งเป็น premium-plan
ในฐานข้อมูล:
Product.create(price_cents: 10000, name: 'Premium Plan', stripe_plan_name: 'premium-plan')
ขั้นตอนที่ 3: สร้างการย้ายข้อมูลเพื่อเพิ่มคอลัมน์ stripe_customer_id
ใน users
โต๊ะ.
เรียกใช้สิ่งต่อไปนี้ในเทอร์มินัล:
rails generate migration AddStripeCustomerIdToUser stripe_customer_id:string rails db:migrate
ขั้นตอนที่ 4: ใช้ตรรกะการสมัครสมาชิกในคลาสบริการ Stripe
เพิ่มอีกสองฟังก์ชันในวิธีส่วนตัวของ app/services/orders/stripe.rb
: execute_subscription
มีหน้าที่สร้างการสมัครรับข้อมูลในวัตถุของลูกค้า ฟังก์ชั่น find_or_create_customer
มีหน้าที่ส่งคืนลูกค้าที่สร้างไว้แล้วหรือส่งคืนลูกค้าที่สร้างขึ้นใหม่
def self.execute_subscription(plan:, token:, customer:) customer.subscriptions.create({ plan: plan }) end def self.find_or_create_customer(card_token:, customer_id:, email:) if customer_id stripe_customer = Stripe::Customer.retrieve({ id: customer_id }) if stripe_customer stripe_customer = Stripe::Customer.update(stripe_customer.id, { source: card_token}) end else stripe_customer = Stripe::Customer.create({ email: email, source: card_token }) end stripe_customer end
สุดท้ายใน execute
ฟังก์ชันในไฟล์เดียวกัน (app/services/orders/stripe.rb
) เราจะเรียก find_or_create_customer
จากนั้นดำเนินการสมัครสมาชิกโดยเรียก execute_subscription
โดยส่งผ่านลูกค้าที่เรียก / สร้างขึ้นก่อนหน้านี้ ดังนั้นแทนที่ความคิดเห็น #SUBSCRIPTIONS WILL BE HANDLED HERE
ใน execute
วิธีการด้วยรหัสต่อไปนี้:
customer = self.find_or_create_customer(card_token: order.token, customer_id: user.stripe_customer_id, email: user.email) if customer user.update(stripe_customer_id: customer.id) order.customer_id = customer.id charge = self.execute_subscription(plan: product.stripe_plan_name, customer: customer)
ขั้นตอนที่ 5: ทดสอบแอปพลิเคชันของคุณ
เยี่ยมชมเว็บไซต์ของคุณเลือกผลิตภัณฑ์การสมัครสมาชิก Premium Plan
และกรอกข้อมูลบัตรทดสอบที่ถูกต้อง หลังจากส่งแล้วควรนำคุณไปยังหน้าที่ประสบความสำเร็จ นอกจากนี้ตรวจสอบในไฟล์ แผงหน้าปัดลาย หากสร้างการสมัครสมาชิกสำเร็จ
การกำหนดค่า PayPal
เช่นเดียวกับที่เราทำใน Stripe เราจะเพิ่มอัญมณีสำหรับการใช้ PayPal API: paypal-sdk-rest
และจำเป็นต้องสร้างบัญชี PayPal ด้วย ขั้นตอนการทำงานเชิงพรรณนาสำหรับ PayPal โดยใช้อัญมณีนี้สามารถปรึกษาได้ในทางการ เอกสาร PayPal API .
ขั้นตอนที่ 1: เพิ่ม paypal-sdk-rest
อัญมณีสำหรับโครงการของคุณ
เพิ่มสิ่งนี้ใน Gemfile
:
gem 'paypal-sdk-rest'
วิ่ง:
bundle install
ขั้นตอนที่ 2: สร้างคีย์ API ของคุณ
ในการมีคีย์ API สำหรับการสื่อสารกับ PayPal คุณจะต้องสร้างบัญชี PayPal ดังนั้น:
- สร้างบัญชี (หรือใช้บัญชี PayPal ของคุณ) ที่ https://developer.paypal.com/ .
- ยังคงลงชื่อเข้าใช้บัญชีของคุณสร้างบัญชีแซนด์บ็อกซ์สองบัญชีที่ https://developer.paypal.com/developer/accounts/ :
- ส่วนบุคคล (บัญชีผู้ซื้อ) - จะใช้ในการทดสอบการชำระเงินและการสมัครสมาชิก
- ธุรกิจ (บัญชีผู้ค้า) - จะเชื่อมโยงกับแอปพลิเคชันซึ่งจะมีคีย์ API ที่เรากำลังมองหา นอกจากนั้นคุณสามารถติดตามธุรกรรมทั้งหมดได้ในบัญชีนี้
- สร้างแอปที่ https://developer.paypal.com/developer/applications โดยใช้บัญชีแซนด์บ็อกซ์ของธุรกิจก่อนหน้านี้
- หลังจากขั้นตอนนี้คุณจะได้รับสองคีย์สำหรับ PayPal:
Client ID
และ Secret
. - ใน
config/application.yml
แทนที่ YOUR_CREDENTIAL_HERE
จาก PAYPAL_CLIENT_ID
และ PAYPAL_CLIENT_SECRET
ด้วยกุญแจที่คุณเพิ่งได้รับ
ขั้นตอนที่ 3: เริ่มต้นโมดูล PayPal
คล้ายกับ Stripe นอกเหนือจากการแทนที่คีย์ใน application.yml
เรายังต้องเริ่มต้นโมดูล PayPal เพื่อให้สามารถใช้คีย์ที่ตั้งค่าไว้แล้วใน ENV
ตัวแปร. เพื่อจุดประสงค์นี้ให้สร้างไฟล์ใน config/initializers/paypal.rb
กับ:
PayPal::SDK.configure( mode: ENV['PAYPAL_ENV'], client_id: ENV['PAYPAL_CLIENT_ID'], client_secret: ENV['PAYPAL_CLIENT_SECRET'], ) PayPal::SDK.logger.level = Logger::INFO
ขั้นตอนที่ 4: รวม PayPal ไว้ที่ส่วนหน้า
ใน index.html.haml
เพิ่มสิ่งนี้ที่ด้านบนของไฟล์:
%script(src='https://www.paypal.com/sdk/js?client-id=#{ENV['PAYPAL_CLIENT_ID']}')
ซึ่งแตกต่างจาก Stripe ตรงที่ PayPal ใช้เพียงปุ่มซึ่งเมื่อคลิกแล้วจะเปิดป๊อปอัปที่ปลอดภัยซึ่งผู้ใช้สามารถเข้าสู่ระบบและดำเนินการชำระเงิน / สมัครสมาชิก ปุ่มนี้สามารถแสดงผลได้โดยเรียกเมธอด paypal.Button(PARAM1).render(PARAM2)
PARAM1
เป็นวัตถุที่มีการกำหนดค่าสภาพแวดล้อมและฟังก์ชันการเรียกกลับสองฟังก์ชันเป็นคุณสมบัติ: createOrder
และ onApprove
. PARAM2
ระบุตัวระบุองค์ประกอบ HTML ที่ควรแนบปุ่ม PayPal
ดังนั้นยังคงอยู่ในไฟล์เดียวกันแทนที่รหัสที่แสดงความคิดเห็น YOUR PAYPAL CODE WILL BE HERE
กับ:
(function setupPaypal() { function isPayment() { return $('[data-charges-and-payments-section] input[name='orders[product_id]']:checked').length } function submitOrderPaypal(chargeID) { var $form = $('#order-details'); // Add a hidden input orders[charge_id] $form.append($('').val(chargeID)); // Set order type $('#order-type').val('paypal'); $form.submit(); } paypal.Buttons({ env: '#{ENV['PAYPAL_ENV']}', createOrder: function() { }, onApprove: function(data) { } }).render('#submit-paypal'); }());
ขั้นตอนที่ 5: ทดสอบแอปพลิเคชันของคุณ
ไปที่หน้าของคุณและตรวจสอบว่าปุ่ม PayPal แสดงขึ้นมาหรือไม่เมื่อคุณเลือก PayPal เป็นวิธีการชำระเงิน
ธุรกรรม PayPal
ตรรกะสำหรับธุรกรรม PayPal ซึ่งแตกต่างจาก Stripe มีความซับซ้อนกว่าเล็กน้อยโดยเกี่ยวข้องกับคำขอเพิ่มเติมที่มาจากส่วนหน้าไปยังส่วนหลัง นั่นคือเหตุผลที่มีส่วนนี้ ฉันจะอธิบายไม่มากก็น้อย (โดยไม่มีรหัส) ว่าฟังก์ชันที่อธิบายไว้ใน createOrder
เป็นอย่างไร และ onApprove
วิธีการที่จะนำไปใช้และสิ่งที่คาดหวังในกระบวนการส่วนหลังด้วย
ขั้นตอนที่ 1: เมื่อผู้ใช้คลิกปุ่มส่ง PayPal ป๊อปอัปของ PayPal ที่ขอข้อมูลรับรองผู้ใช้จะเปิดขึ้น แต่อยู่ในสถานะโหลด ฟังก์ชันเรียกกลับ createOrder
ถูกเรียก.
ป๊อปอัพ PayPal สถานะกำลังโหลด ขั้นตอนที่ 2: ในฟังก์ชั่นนี้เราจะดำเนินการร้องขอไปยังส่วนหลังของเราซึ่งจะสร้างการชำระเงิน / การสมัครสมาชิก นี่คือจุดเริ่มต้นของการทำธุรกรรมและจะไม่มีการเรียกเก็บเงินใด ๆ ทั้งสิ้นดังนั้นธุรกรรมจึงอยู่ในรูปแบบ รอดำเนินการ สถานะ. แบ็คเอนด์ของเราควรคืนโทเค็นให้เราซึ่งจะสร้างขึ้นโดยใช้โมดูล PayPal (ให้ผ่าน paypal-rest-sdk
gem)
ขั้นตอนที่ 3: ยังอยู่ createOrder
โทรกลับเราจะส่งคืนโทเค็นนี้ที่สร้างขึ้นในส่วนหลังของเราและหากทุกอย่างเรียบร้อยป๊อปอัปของ PayPal จะแสดงสิ่งต่อไปนี้โดยขอข้อมูลรับรองผู้ใช้:
ป๊อปอัพ PayPal ข้อมูลรับรองผู้ใช้ ขั้นตอนที่ 4: หลังจากผู้ใช้เข้าสู่ระบบและเลือกวิธีการชำระเงินป๊อปอัปจะเปลี่ยนสถานะเป็นดังต่อไปนี้:
ป๊อปอัพ PayPal ธุรกรรมที่ได้รับอนุญาต ขั้นตอนที่ 5: onApprove
เรียกใช้ฟังก์ชันเรียกกลับแล้ว เราได้กำหนดไว้ดังต่อไปนี้: onApprove: function(data)
. data
วัตถุจะมีข้อมูลการชำระเงินเพื่อดำเนินการ ในการโทรกลับนี้จะมีการร้องขออีกครั้งไปยังฟังก์ชันแบ็คเอนด์ของเราในครั้งนี้โดยส่งผ่านออบเจ็กต์ข้อมูลเพื่อดำเนินการตามคำสั่งของ PayPal
ขั้นตอนที่ 6: แบ็คเอนด์ของเราดำเนินการธุรกรรมนี้และส่งคืน 200 (หากสำเร็จ)
ขั้นตอนที่ 7: เมื่อส่วนหลังของเราส่งคืนเราจะส่งแบบฟอร์ม นี่เป็นคำขอที่สามที่เราส่งไปยังส่วนหลังของเรา
โปรดทราบว่าแตกต่างจาก Stripe ตรงที่มีคำขอสามรายการที่ส่งไปยังส่วนหลังของเราในกระบวนการนี้ และเราจะทำให้สถานะการบันทึกคำสั่งซื้อของเราตรงกัน:
createOrder
โทรกลับ: มีการสร้างธุรกรรมและสร้างบันทึกการสั่งซื้อด้วย ดังนั้นจึงอยู่ในรูปแบบ รอดำเนินการ สถานะเป็นค่าเริ่มต้น onApprove
โทรกลับ: ธุรกรรมถูกดำเนินการและคำสั่งของเราจะถูกตั้งค่าเป็น paypal_execute . - ส่งหน้าคำสั่งซื้อ: ธุรกรรมได้ดำเนินการไปแล้วจึงไม่มีอะไรเปลี่ยนแปลง บันทึกคำสั่งซื้อจะเปลี่ยนสถานะเป็น จ่าย .
กระบวนการทั้งหมดนี้อธิบายไว้ในกราฟต่อไปนี้:
ธุรกรรม PayPal การชำระเงินด้วย PayPal
การชำระเงินด้วย PayPal เป็นไปตามตรรกะเดียวกันกับการเรียกเก็บเงินแบบ Stripe ดังนั้นจึงเป็นตัวแทนของการทำธุรกรรมครั้งเดียว แต่ดังที่ได้กล่าวไว้ในหัวข้อก่อนหน้านี้มีตรรกะการไหลที่แตกต่างกัน นี่คือการเปลี่ยนแปลงที่จะต้องดำเนินการสำหรับการจัดการการชำระเงินด้วย PayPal:
ขั้นตอนที่ 1: สร้างเส้นทางใหม่สำหรับ PayPal และดำเนินการชำระเงิน
เพิ่มเส้นทางต่อไปนี้ใน config/routes.rb
:
post 'orders/paypal/create_payment' => 'orders#paypal_create_payment', as: :paypal_create_payment post 'orders/paypal/execute_payment' => 'orders#paypal_execute_payment', as: :paypal_execute_payment
สิ่งนี้จะสร้างเส้นทางใหม่สองเส้นทางสำหรับการสร้างและดำเนินการชำระเงินซึ่งจะจัดการใน paypal_create_payment
และ paypal_execute_payment
วิธีการควบคุมคำสั่งซื้อ
ขั้นตอนที่ 2: สร้างบริการ PayPal
เพิ่มคลาสซิงเกิลตัน Orders::Paypal
ที่: app/services/orders/paypal.rb
.
บริการนี้ในขั้นต้นจะมีหน้าที่รับผิดชอบสามประการ:
create_payment
วิธีสร้างการชำระเงินโดยการโทร PayPal::SDK::REST::Payment.new
ก โทเค็น ถูกสร้างขึ้นและส่งกลับไปยังส่วนหน้า execute_payment
วิธีดำเนินการชำระเงินโดยการค้นหาวัตถุการชำระเงินที่สร้างไว้ก่อนหน้าผ่าน PayPal::SDK::REST::Payment.find(payment_id)
ซึ่งใช้ไฟล์ payment_id เป็นอาร์กิวเมนต์ที่มีค่าเดียวกับ charge_id เก็บไว้ในขั้นตอนก่อนหน้าในวัตถุคำสั่ง หลังจากนั้นเราโทรไปที่ execute
ในออบเจ็กต์การชำระเงินโดยมีผู้ชำระเงินที่ระบุเป็นพารามิเตอร์ ผู้ชำระเงินนี้จะได้รับโดยส่วนหน้าหลังจากที่ผู้ใช้ให้ข้อมูลรับรองและเลือกวิธีการชำระเงินในป๊อปอัป finish
วิธีค้นหาคำสั่งซื้อโดยเฉพาะ charge_id การค้นหาคำสั่งซื้อที่เพิ่งสร้างขึ้นในไฟล์ paypal_execute สถานะ. หากพบบันทึกจะถูกทำเครื่องหมายว่าชำระแล้ว
class Orders::Paypal def self.finish(charge_id) order = Order.paypal_executed.recently_created.find_by(charge_id: charge_id) return nil if order.nil? order.set_paid order end def self.create_payment(order:, product:) payment_price = (product.price_cents/100.0).to_s currency = 'USD' payment = PayPal::SDK::REST::Payment.new({ intent: 'sale', payer: { payment_method: 'paypal' }, redirect_urls: { return_url: '/', cancel_url: '/' }, transactions: [{ item_list: { items: [{ name: product.name, sku: product.name, price: payment_price, currency: currency, quantity: 1 } ] }, amount: { total: payment_price, currency: currency }, description: 'Payment for: #{product.name}' }] }) if payment.create order.token = payment.token order.charge_id = payment.id return payment.token if order.save end end def self.execute_payment(payment_id:, payer_id:) order = Order.recently_created.find_by(charge_id: payment_id) return false unless order payment = PayPal::SDK::REST::Payment.find(payment_id) if payment.execute( payer_id: payer_id ) order.set_paypal_executed return order.save end end
ขั้นตอนที่ 3: เรียกใช้บริการ PayPal ในตัวควบคุมในการดำเนินการส่ง
เพิ่มการโทรกลับสำหรับ prepare_new_order
ก่อนดำเนินการ paypal_create_payment
(ซึ่งจะถูกเพิ่มในขั้นตอนถัดไป) โดยการเพิ่มสิ่งต่อไปนี้ในไฟล์ app/controllers/orders_controller.rb
:
class OrdersController อีกครั้งในไฟล์เดียวกันให้เรียกใช้บริการ PayPal ในการดำเนินการส่งโดยแทนที่รหัสที่แสดงความคิดเห็น #PAYPAL WILL BE HANDLED HERE.
ดังต่อไปนี้:
... elsif order_params[:payment_gateway] == 'paypal' @order = Orders::Paypal.finish(order_params[:token]) end ...
ขั้นตอนที่ 4: สร้างการดำเนินการสำหรับจัดการคำขอ
ยังคงอยู่ใน app/controllers/orders_controller.rb
สร้างการดำเนินการใหม่สองรายการ (ซึ่งควรเป็นสาธารณะ) สำหรับจัดการคำขอไปยัง paypal_create_payment
และ paypal_execute_payment
เส้นทาง:
paypal_create_payment
วิธีการ: จะเรียกวิธีการบริการของเรา create_payment
. หากส่งคืนสำเร็จก็จะส่งคืนคำสั่งซื้อ โทเค็น สร้างโดย Orders::Paypal.create_payment
. paypal_execute_payment
วิธีการ: จะเรียกวิธีการบริการของเรา execute_payment
(ซึ่งดำเนินการชำระเงินของเรา) หากดำเนินการชำระเงินสำเร็จจะส่งคืน 200
... def paypal_create_payment result = Orders::Paypal.create_payment(order: @order, product: @product) if result render json: { token: result }, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end def paypal_execute_payment if Orders::Paypal.execute_payment(payment_id: params[:paymentID], payer_id: params[:payerID]) render json: {}, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end ...
ขั้นตอนที่ 5: ใช้ฟังก์ชันเรียกกลับส่วนหน้าสำหรับ createOrder
และ onApprove
.
ทำให้ paypal.Button.render
ของคุณ การโทรมีลักษณะดังนี้:
paypal.Buttons({ env: '#{ENV['PAYPAL_ENV']}', createOrder: function() { $('#order-type').val('paypal'); if (isPayment()) { return $.post('#{paypal_create_payment_url}', $('#order-details').serialize()).then(function(data) { return data.token; }); } else { } }, onApprove: function(data) { if (isPayment()) { return $.post('#{paypal_execute_payment_url}', { paymentID: data.paymentID, payerID: data.payerID }).then(function() { submitOrderPaypal(data.paymentID) }); } else { } } }).render('#submit-paypal');
ดังที่ได้กล่าวไว้ในหัวข้อก่อนหน้านี้เราเรียกว่า paypal_create_payment_url
สำหรับ createOrder
โทรกลับและ paypal_execute_payment_url
สำหรับ onApprove
โทรกลับ. โปรดสังเกตว่าหากคำขอสุดท้ายส่งคืนสำเร็จเราจะส่งคำสั่งซื้อซึ่งเป็นคำขอที่สามที่ส่งไปยังเซิร์ฟเวอร์
ใน createOrder
ตัวจัดการฟังก์ชันเราส่งคืนโทเค็น (ได้รับจากส่วนหลัง) ใน onApprove
โทรกลับเรามีคุณสมบัติสองอย่างที่ส่งผ่านไปยังส่วนหลังของเรา paymentID
และ payerID
. สิ่งเหล่านี้จะถูกใช้เพื่อดำเนินการชำระเงิน
สุดท้ายสังเกตว่าเรามีสองว่าง else
ประโยคเมื่อฉันกำลังออกจากที่ว่างสำหรับส่วนถัดไปซึ่งเราจะเพิ่มการสมัครสมาชิก PayPal
หากคุณเข้าชมเพจของคุณหลังจากที่ผสานรวมส่วน front-end JavaScript และเลือก PayPal เป็นวิธีการชำระเงินควรมีลักษณะดังนี้:
หน้าดัชนีหลังจากรวมเข้ากับ PayPal ขั้นตอนที่ 6: ทดสอบแอปพลิเคชันของคุณ
- ไปที่หน้าดัชนี
- เลือกผลิตภัณฑ์ชำระเงิน / เรียกเก็บเงินและ PayPal เป็นวิธีการชำระเงิน
- คลิกที่ปุ่มส่ง PayPal
- ในป๊อปอัป PayPal:
- ใช้ข้อมูลรับรองสำหรับบัญชีผู้ซื้อที่คุณสร้างขึ้น
- เข้าสู่ระบบและยืนยันคำสั่งซื้อของคุณ
- ป๊อปอัปควรปิด
- ตรวจสอบว่าคุณถูกเปลี่ยนเส้นทางไปยังหน้าความสำเร็จหรือไม่
- สุดท้ายตรวจสอบว่ามีการดำเนินการสั่งซื้อในบัญชี PayPal หรือไม่โดยลงชื่อเข้าใช้ด้วยบัญชีธุรกิจของคุณที่ https://www.sandbox.paypal.com/signin และตรวจสอบแดชบอร์ด https://www.sandbox.paypal.com/listing/transactions .
การสมัครสมาชิก PayPal
แผน / ข้อตกลง / การสมัครสมาชิกของ PayPal เป็นไปตามตรรกะเดียวกันกับการสมัครสมาชิก Stripe และสร้างขึ้นสำหรับการชำระเงินที่เกิดขึ้นประจำ ด้วยผลิตภัณฑ์ประเภทนี้ผู้ใช้จะถูกเรียกเก็บเงินรายวันรายสัปดาห์รายเดือนหรือรายปีโดยอัตโนมัติตาม การกำหนดค่า .
เราจะใช้ฟิลด์สำหรับผลิตภัณฑ์ paypal_plan_name
เพื่อจัดเก็บ ID แผนที่ PayPal ให้ไว้ ในกรณีนี้แตกต่างจาก Stripe ตรงที่เราไม่ได้เลือก ID และ PayPal จะส่งคืนค่านี้ซึ่งจะใช้ในการอัปเดตผลิตภัณฑ์ล่าสุดที่สร้างในฐานข้อมูลของเรา
สำหรับการสร้างการสมัครสมาชิกไม่มี customer
จำเป็นต้องมีข้อมูลในขั้นตอนใด ๆ เช่นวิธีการ onApprove
อาจจัดการการเชื่อมโยงนี้ในการนำไปใช้งาน ดังนั้นตารางของเราจะยังคงเหมือนเดิม
ขั้นตอนที่ 1: สร้างแผนโดยใช้ PayPal API
เปิดคอนโซลของคุณโดยใช้คำสั่ง rails c
สร้างการสมัครสำหรับบัญชี PayPal ของคุณด้วย:
plan = PayPal::SDK::REST::Plan.new({ name: 'Premium Plan', description: 'Premium Plan', type: 'fixed', payment_definitions: [{ name: 'Premium Plan', type: 'REGULAR', frequency_interval: '1', frequency: 'MONTH', cycles: '12', amount: { currency: 'USD', value: '100.00' } }], merchant_preferences: { cancel_url: 'http://localhost:3000/', return_url: 'http://localhost:3000/', max_fail_attempts: '0', auto_bill_amount: 'YES', initial_fail_amount_action: 'CONTINUE' } }) plan.create plan_update = { op: 'replace', path: '/', value: { state: 'ACTIVE' } } plan.update(plan_update)
ขั้นตอนที่ 2: อัปเดตผลิตภัณฑ์ล่าสุดในฐานข้อมูล paypal_plan_name
พร้อมส่งคืน plan.id
.
วิ่ง:
Product.last.update(paypal_plan_name: plan.id)
ขั้นตอนที่ 3: เพิ่มเส้นทางสำหรับการสมัครสมาชิก PayPal
เพิ่มสองเส้นทางใหม่ใน config/routes.rb
:
post 'orders/paypal/create_subscription' => 'orders#paypal_create_subscription', as: :paypal_create_subscription post 'orders/paypal/execute_subscription' => 'orders#paypal_execute_subscription', as: :paypal_execute_subscription
ขั้นตอนที่ 4: จัดการการสร้างและดำเนินการในบริการ PayPal
เพิ่มอีกสองฟังก์ชันสำหรับการสร้างและดำเนินการสมัครสมาชิกใน Orders::Paypal
ของ app/services/orders/paypal.rb
:
def self.create_subscription(order:, product:) agreement = PayPal::SDK::REST::Agreement.new({ name: product.name, description: 'Subscription for: #{product.name}', start_date: (Time.now.utc + 1.minute).iso8601, payer: { payment_method: 'paypal' }, plan: { id: product.paypal_plan_name } }) if agreement.create order.token = agreement.token return agreement.token if order.save end end def self.execute_subscription(token:) order = Order.recently_created.find_by(token: token) return false unless order agreement = PayPal::SDK::REST::Agreement.new agreement.token = token if agreement.execute order.charge_id = agreement.id order.set_paypal_executed return order.charge_id if order.save end end
ใน create_subscription
เราเริ่มต้นข้อตกลงโดยเรียกเมธอด PayPal::SDK::REST::Agreement.new
และผ่าน product.paypal_plan_name
เป็นหนึ่งในคุณลักษณะของมัน หลังจากนั้นเราสร้างมันและตอนนี้โทเค็นจะถูกตั้งค่าสำหรับออบเจ็กต์สุดท้ายนี้ เรายังส่งคืนโทเค็นไปที่ส่วนหน้า
ใน execute_subscription
เราพบ order
บันทึกที่สร้างขึ้นในการโทรครั้งก่อน หลังจากนั้นเราเริ่มต้นข้อตกลงใหม่เราตั้งค่าโทเค็นของวัตถุก่อนหน้านี้และดำเนินการ หากขั้นตอนสุดท้ายนี้ดำเนินการสำเร็จสถานะคำสั่งซื้อจะถูกตั้งค่าเป็น paypal_execute . และตอนนี้เรากลับไปที่ส่วนหน้าของรหัสข้อตกลงซึ่งเก็บไว้ใน order.chager_id
ขั้นตอนที่ 5: เพิ่มการดำเนินการสำหรับสร้างและดำเนินการสมัครสมาชิกใน orders_controller
เปลี่ยน app/controllers/orders_controller.rb
. ที่ด้านบนสุดของคลาสอันดับแรกจากนั้นอัปเดตการติดต่อกลับ prepare_new_order
ที่จะดำเนินการก่อนหน้านี้ paypal_create_subscription
ถูกเรียก:
class OrdersController นอกจากนี้ในไฟล์เดียวกันจะเพิ่มฟังก์ชันสาธารณะสองฟังก์ชันเพื่อให้เรียกว่า Orders::Paypal
บริการที่มีขั้นตอนเดียวกันกับที่เรามีอยู่แล้วในการชำระเงินด้วย PayPal:
... def paypal_create_subscription result = Orders::Paypal.create_subscription(order: @order, product: @product) if result render json: { token: result }, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end def paypal_execute_subscription result = Orders::Paypal.execute_subscription(token: params[:subscriptionToken]) if result render json: { id: result}, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end ...
ขั้นตอนที่ 6: การเพิ่มตัวจัดการการสมัครสมาชิกสำหรับ createOrder
และ onApprove
การเรียกกลับในส่วนหน้า
สุดท้ายใน index.html.haml
แทนที่ paypal.Buttons
ฟังก์ชันต่อไปนี้ซึ่งจะเติมสองว่าง else
เรามีมาก่อน:
paypal.Buttons({ env: '#{ENV['PAYPAL_ENV']}', createOrder: function() { $('#order-type').val('paypal'); if (isPayment()) { return $.post('#{paypal_create_payment_url}', $('#order-details').serialize()).then(function(data) { return data.token; }); } else { return $.post('#{paypal_create_subscription_url}', $('#order-details').serialize()).then(function(data) { return data.token; }); } }, onApprove: function(data) { if (isPayment()) { return $.post('#{paypal_execute_payment_url}', { paymentID: data.paymentID, payerID: data.payerID }).then(function() { submitOrderPaypal(data.paymentID) }); } else { return $.post('#{paypal_execute_subscription_url}', { subscriptionToken: data.orderID }).then(function(executeData) { submitOrderPaypal(executeData.id) }); } } }).render('#submit-paypal');
การสร้างและการดำเนินการสำหรับการสมัครสมาชิกมีตรรกะที่คล้ายกันกับที่ใช้สำหรับการชำระเงิน ความแตกต่างอย่างหนึ่งคือเมื่อดำเนินการชำระเงินข้อมูลจากฟังก์ชันเรียกกลับ onApprove
มี paymentID
แล้ว เป็นตัวแทนของ charge_id
เพื่อส่งแบบฟอร์มผ่าน submitOrderPaypal(data.paymentID)
. สำหรับการสมัครสมาชิกเราได้รับ charge_id
หลังจากดำเนินการแล้วโดยขอ POST
บน paypal_execute_subscription_url
เพื่อให้เราโทรได้ submitOrderPaypal(executeData.id)
ขั้นตอนที่ 7: ทดสอบแอปพลิเคชันของคุณ
- ไปที่หน้าดัชนี
- เลือกผลิตภัณฑ์สมัครสมาชิกและ PayPal เป็นวิธีการชำระเงิน
- คลิกที่ปุ่มส่ง PayPal
- ในป๊อปอัป PayPal:
- ใช้ข้อมูลรับรองสำหรับบัญชีผู้ซื้อที่คุณสร้างขึ้น
- เข้าสู่ระบบและยืนยันคำสั่งซื้อของคุณ
- ป๊อปอัปควรปิด
- ตรวจสอบว่าคุณถูกเปลี่ยนเส้นทางไปยังหน้าความสำเร็จหรือไม่
- สุดท้ายตรวจสอบว่ามีการดำเนินการสั่งซื้อในบัญชี PayPal หรือไม่โดยลงชื่อเข้าใช้ด้วยบัญชีธุรกิจของคุณที่ https://www.sandbox.paypal.com/signin และตรวจสอบแดชบอร์ด https://www.sandbox.paypal.com/listing/transactions .
สรุป
หลังจากอ่านบทความนี้คุณควรจะสามารถรวมการชำระเงิน / ค่าใช้จ่ายตลอดจนธุรกรรมการสมัครสมาชิกสำหรับ PayPal และ Stripe ในแอปพลิเคชัน Rails ของคุณ มีหลายประเด็นที่ควรปรับปรุงซึ่งฉันไม่ได้เพิ่มในบทความนี้เพราะความสั้น ฉันจัดระเบียบทุกอย่างตามข้อสันนิษฐานของความยาก:
- ง่ายกว่า:
- ใช้ Transport Layer Security (TLS) เพื่อให้คำขอของคุณใช้ HTTPS
- ใช้การกำหนดค่าสภาพแวดล้อมการผลิตสำหรับทั้ง PayPal และ Stripe
- เพิ่มหน้าใหม่เพื่อให้ผู้ใช้สามารถเข้าถึงประวัติการสั่งซื้อก่อนหน้านี้
- ปานกลาง:
- คืนเงินหรือยกเลิกการสมัครสมาชิก
- จัดเตรียมโซลูชันสำหรับการชำระเงินของผู้ใช้ที่ไม่ได้ลงทะเบียน
- ยากกว่า:
- ให้วิธีลบบัญชีและเก็บรักษาไว้ โทเค็น และ รหัสลูกค้า หากผู้ใช้ต้องการกลับมา แต่หลังจากผ่านไปสักระยะหนึ่งให้ลบข้อมูลนี้ออกเพื่อให้แอปพลิเคชันของคุณสอดคล้องกับ PCI มากขึ้น
- ย้ายไปที่ PayPal เวอร์ชัน 2 API ในฝั่งเซิร์ฟเวอร์ ( https://developer.paypal.com/docs/api/payments/v2/ ) อัญมณีที่เราใช้ในบทช่วยสอนนี้ paypal-sdk-rest มีเฉพาะรุ่นเบต้าสำหรับเวอร์ชัน 2 เพื่อให้สามารถใช้งานได้อย่างระมัดระวัง ( https://github.com/paypal/PayPal-Ruby-SDK/tree/2.0-beta ).
- รวมคำขอที่มีศักยภาพ
ฉันขอแนะนำให้อ่านเกี่ยวกับองค์ประกอบ Stripe Checkout ซึ่งเป็นอีกวิธีหนึ่งในการรวม Stripe ไว้ที่ส่วนหน้า ซึ่งแตกต่างจาก Stripe Elements ที่เราใช้ในบทช่วยสอนนี้ Stripe Checkout จะเปิดป๊อปอัปหลังจากคลิกที่ปุ่ม (คล้ายกับ PayPal) ที่ผู้ใช้กรอกข้อมูลบัตรเครดิตหรือเลือกชำระเงินด้วย Google Pay / Apple Pay https://stripe.com/docs/web .
คำแนะนำในการอ่านครั้งที่สองคือหน้าการรักษาความปลอดภัยสำหรับทั้งเกตเวย์การชำระเงิน
สุดท้ายนี้ขอขอบคุณที่อ่านบทความนี้! คุณยังสามารถตรวจสอบไฟล์ โครงการ GitHub ที่ใช้สำหรับตัวอย่างโครงการนี้ . ที่นั่นฉันเพิ่ม rspec การทดสอบเช่นกันในขณะที่พัฒนา
ทำความเข้าใจพื้นฐาน
Stripe คืออะไรและทำงานอย่างไร?
Stripe เป็น บริษัท ที่พัฒนาซอฟต์แวร์สำหรับบุคคลหรือธุรกิจเพื่อดำเนินการชำระเงินที่ปลอดภัยผ่านอินเทอร์เน็ต
ราง 4 กับราง 5
ความแตกต่างระหว่าง PayPal และ Stripe คืออะไร?
พวกเขาเสนอแอปพลิเคชันที่แตกต่างกันเกี่ยวกับการชำระเงินและมีค่าธรรมเนียมในการใช้บริการที่แตกต่างกัน
โทเค็นวิธีการชำระเงินคืออะไร?
การชำระเงินโทเค็นเป็นกระบวนการจัดการข้อมูลที่ละเอียดอ่อนจากผู้ใช้และเปลี่ยนเป็นโทเค็นดังนั้นจึงไม่มีข้อมูลที่ละเอียดอ่อนรั่วไหล
PayPal เป็นเกตเวย์การชำระเงินหรือตัวประมวลผลหรือไม่
PayPal ไม่ใช่เกตเวย์ แต่เป็นโซลูชันสำหรับผู้ค้าที่สมบูรณ์ อย่างไรก็ตามจะใช้เกตเวย์การชำระเงินที่เรียกว่า Payflow
Stripe เป็นเกตเวย์การชำระเงินหรือตัวประมวลผลหรือไม่
Stripe เป็นเกตเวย์การชำระเงินที่จัดการบัตรของลูกค้า