AliExpress、Ebay、Amazonなどの巨大なeコマース企業にとって重要な機能は、支払いを安全に処理する方法であり、これは彼らのビジネスに不可欠です。この機能が失敗した場合、その結果は壊滅的なものになります。これは業界のリーダーに適用され、 Ruby onRails開発者 eコマースアプリに取り組んでいます。
サイバーセキュリティは攻撃を防ぐために不可欠であり、トランザクションプロセスをより安全にする方法は、サードパーティのサービスにそれを処理するように依頼することです。アプリケーションに支払いゲートウェイを含めることは、ユーザー承認、データ暗号化、およびダッシュボードを提供するため、この目標を達成する方法であり、トランザクションのステータスをその場で追跡できます。
ウェブ上にはさまざまなペイメントゲートウェイサービスがありますが、この記事では統合に焦点を当てます 縞 そして PayPal Railsアプリケーションに。他のいくつかに言及すると:Amazon Payments、Square、SecurePay、WorldPay、Authorize.Net、2Checkout.com、Braintree、Amazon、またはBlueSnap。
一般に、ユーザーがログイン/クレジットカードデータを挿入できるフォーム/ボタンがアプリケーションにあります。 PayPalとStripeは、iframe
を使用することで、この最初のステップをより安全にしています。フォームまたはpopups
これにより、アプリケーションはこのトランザクションを表すトークンを返すため、機密性の高いユーザーのクレジットカード情報を保存できなくなります。一部のユーザーは、サードパーティのサービスがトランザクションプロセスを処理していることを知っていることで、支払いを処理することにすでに自信を持っているかもしれません。そのため、これもアプリケーションの魅力になります。
ユーザー情報を認証した後、支払いゲートウェイは、支払いを決済するために銀行と通信する支払い処理業者に連絡することによって支払いを確認します。これにより、トランザクションが適切に借方/貸方に記入されます。
Stripeは、クレジットカード番号、cvv、および有効期限を尋ねるクレジットカードフォームを使用します。したがって、ユーザーはセキュリティで保護されたStripe入力にクレジットカード情報を入力する必要があります。この情報を提供した後、アプリケーションのバックエンドはトークンを介してこの支払いを処理します。
Stripeとは異なり、PayPalはユーザーをPayPalログインページにリダイレクトします。ユーザーはPayPalを介して支払い方法を承認および選択します。この場合も、バックエンドはユーザーの機密データの代わりにトークンを処理します。
これらの2つの支払いゲートウェイの場合、バックエンドは、OK / NOK応答を返すStripeまたはPayPalAPIを介してトランザクションの実行を続行するように要求する必要があるため、アプリケーションはそれに応じてユーザーを成功ページまたはエラーページにリダイレクトする必要があることに注意してください。
この記事の目的は、これら2つの支払いゲートウェイを単一のアプリケーションに統合するためのクイックガイドを提供することです。すべてのテストで、支払いをシミュレートするために、StripeとPayPalが提供するサンドボックスとテストアカウントを使用します。
支払いゲートウェイを統合する前に、gem、データベーステーブル、およびインデックスページを追加してアプリケーションを初期化するためのセットアップを行います。このプロジェクトは、Railsバージョン5.2.3とRuby2.6.3を使用して作成されました。
注意: あなたは新しいをチェックアウトすることができます 最近の記事のRails6の機能 。
ステップ1: Railsアプリケーションを初期化します。
rails
を使用してプロジェクトの初期化を実行し、プロジェクトを初期化します。アプリ名を使用したコマンド:
rails new YOUR_APP_NAME
そしてcd
アプリケーションフォルダにあります。
ステップ2: gemをインストールします。
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: 宝石を初期化します。
これらのgemのいくつかは、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: テーブルと移行
このプロジェクトでは3つのテーブルが使用されます ユーザー 、 製品 、および 注文 。
Users
:デバイスによって生成されますProducts
列:name
price_cents
Stripe_plan_name
:Stripeで作成されたサブスクリプションプランを表すID。ユーザーはそれをサブスクライブできます。このフィールドは、Stripeプランに関連付けられている製品にのみ必要です。paypal_plan_name
:stripe_plan_name
と同じしかしPayPalの場合Orders
列:product_id
user_id
status
:注文が保留中、失敗、または支払い済みの場合に通知されます。token
:これは、トランザクションを初期化するためにAPI(StripeまたはPayPal)から生成されたトークンです。price_cents
:製品と同様ですが、この値を注文レコードで永続化するために使用されますpayment_gateway
:PayPalまたはStripeの注文に使用されている支払いゲートウェイを保存しますcustomer_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: モデルを作成します。
ユーザーモデルはデバイスのインストールからすでに作成されており、変更する必要はありません。その上、2つのモデルが作成されます 製品 そして 注文 。
製品。 新しいファイル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: データベースにデータを入力します。
ユーザーと2つの製品がコンソールに作成されます。注文記録は、支払いテストに従って作成されます。
- 実行
rails s
- ブラウザで
http://localhost:3000
にアクセスします - サインアップページにリダイレクトされます。
- メールアドレスとパスワードを入力して、ユーザーを登録します。
- ターミナルでは、データベースにユーザーが作成されたことを示す次のログが表示されます。
User Create (0.1ms) INSERT INTO 'users' ('email', 'encrypted_password', 'created_at', 'updated_at') VALUES (?, ?, ?, ?) …
rails c
を実行して、サブスクリプションなしで2つの製品を作成しますと追加: 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
アクションは、フロントエンドで消費される2つの変数を格納します:@products_purchase
計画のない製品のリストと@products_subscription
がありますPayPalとStripeの両方のプランの製品があります。
class OrdersController app/views/orders/index.html.haml
にファイルを作成します。このファイルには、送信方法を介してバックエンドに送信するすべての入力と、支払いゲートウェイと製品選択の相互作用が含まれています。入力名の属性は次のとおりです。
Orders[product_id]
製品IDを格納します。 Orders[payment_gateway]
ストライプまたは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によって追跡されないファイルに保存されます。このファイルには、ペイメントゲートウェイごとに2種類のキーが保存されています。ここでは、それらにダミー値を使用します。これらのキーを作成するための追加の指示は、以降のセクションに示されています。
ステップ1: これを.gitignore
に追加します。
/config/application.yml
ステップ2: config/application.yml
に資格情報を使用してファイルを作成します。これらのAPIにアクセスするためのすべてのPayPalおよびStripeサンドボックス/テストキーが含まれている必要があります。
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 APIを使用するためのgemを追加します:stripe-rails
。料金とサブスクリプションを処理できるように、Stripeアカウントを作成することも必要です。必要に応じて、StripeAPIのAPIメソッドを参照できます。 公式ドキュメント 。
ステップ1: ストライプレールの宝石をプロジェクトに追加します。
ザ・ ストライプレールの宝石 このプロジェクトで使用されるすべてのAPIリクエストのインターフェースを提供します。
これをGemfile
に追加します。
gem 'stripe-rails'
実行:
bundle install
ステップ2: APIキーを生成します。
Stripeと通信するためのAPIキーを取得するには、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が提供)を使用して、Stripejavascriptライブラリがユーザーのページに追加されます。
= stripe_javascript_tag
Stripeは、APIを介して作成された安全な入力フィールドを使用します。 iframe
で作成されるためこのAPIを介して作成されているため、ユーザーのクレジットカード情報を処理する可能性のある脆弱性について心配する必要はありません。さらに、バックエンドはユーザーの機密データを処理/保存することができず、この情報を表すトークンのみを受け取ります。
これらの入力フィールドは、stripe.elements().create('card')
を呼び出すことによって作成されます。その後、返されたオブジェクトをmount()
で呼び出す必要があります。これらの入力をマウントする必要があるHTML要素ID /クラスを引数として渡すことによって。詳細については、次のURLをご覧ください。 縞 。
ユーザーがStripe支払い方法で送信ボタンを押すと、作成されたStripeカード要素に対してpromiseを返す別のAPI呼び出しが実行されます。
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セキュア入力フィールドで次のようになります。
Stripeセキュア入力フィールドと統合されたインデックスページ。 ステップ5: アプリケーションをテストします。
クレジットカードフォームにテストカードを記入します( https://stripe.com/docs/testing )ページを送信します。 submit
かどうかを確認しますアクションはすべてのパラメーターで呼び出されます( 製品番号 、 Payment_gateway 、および トークン )サーバー出力で。
ストライプチャージ
ストライプ料金は1回限りのトランザクションを表します。したがって、Stripeの請求トランザクションの後、クライアントから直接お金を受け取ります。これは、プランに関連付けられていない製品の販売に最適です。後のセクションで、PayPalで同じトランザクションタイプを実行する方法を示しますが、このタイプのトランザクションのPayPalの名前は 支払い 。
このセクションでは、注文を処理および送信するためのすべてのスケルトンも提供します。 submit
で注文を作成しますStripeフォームが送信されたときのアクション。この注文には最初に 保留中 ステータスなので、この注文の処理中に問題が発生した場合でも、注文は 保留中 。
Stripe API呼び出しでエラーが発生した場合は、 失敗しました 状態であり、充電が正常に完了すると、 有料 状態。次のグラフに示すように、ユーザーはStripeAPI応答に従ってリダイレクトされます。
ストライプトランザクション。 また、ストライプチャージを行うとIDが返されます。このIDは、後で必要に応じてStripeダッシュボードで検索できるように保存されます。このIDは、注文の払い戻しが必要な場合にも使用できます。この記事では、そのようなことについては説明しません。
ステップ1: Stripeサービスを作成します。
Stripe APIを使用してStripe操作を表すために、シングルトンクラスを使用します。料金を作成するには、メソッドStripe::Charge.create
が呼び出され、返されたオブジェクトID属性が注文レコードcharge_id
に保存されます。これcreate
関数は、フロントエンドで発生したトークン、注文価格、および説明を渡すことによって呼び出されます。
したがって、新しいフォルダーapp/services/orders
を作成し、Stripeサービスを追加します:app/services/orders/stripe.rb
Orders::Stripe
を含むメソッド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
。 2つの新しいプライベート関数も追加されたことに注意してください: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_plan_name
のフィールドを使用します。プランIDを保存するために—実際にはIDを選択することが可能であり、それをpremium-plan
と呼びます—これは関係customer subscription
を作成するために使用されます。
また、stripe_customer_id
というユーザーテーブルの新しい列を作成します。 Stripeカスタマーオブジェクトのidプロパティで埋められます。関数Stripe::Customer.create
の場合、Stripeカスタマーが作成されます。が呼び出され、アカウントに作成およびリンクされている顧客を( https://dashboard.stripe.com/test/customers )。顧客はsource
を渡すことによって作成されますこの場合、フォームが送信されたときに送信されるフロントエンドで生成されたトークンであるパラメーター。
最後に述べたStripeAPI呼び出しから取得した顧客オブジェクトは、customer.subscriptions.create
を呼び出すことによって実行されるサブスクリプションの作成にも使用されます。プランIDをパラメータとして渡します。
さらに、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: StripeAPIを使用してプランを作成します。
コマンドrails c
を使用してコンソールを開きます。次のコマンドを使用して、Stripeアカウントのサブスクリプションを作成します。
Stripe::Plan.create({ amount: 10000, interval: 'month', product: { name: 'Premium plan', }, currency: 'usd', id: 'premium-plan', })
このステップで返された結果がtrueの場合、プランが正常に作成されたことを意味し、でアクセスできます。 ストライプダッシュボード 。
ステップ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
のプライベートメソッドにさらに2つの関数を追加します: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: アプリケーションをテストします。
Webサイトにアクセスし、サブスクリプション製品Premium Plan
を選択して、有効なテストカードに入力します。送信後、成功したページにリダイレクトされます。さらに、 ストライプダッシュボード サブスクリプションが正常に作成された場合。
PayPalの設定
Stripeで行ったように、PayPal APIを使用するためのgem:paypal-sdk-rest
も追加します。また、PayPalアカウントの作成も必要です。このgemを使用したPayPalの説明的なワークフローは、公式で参照できます。 PayPalAPIドキュメント 。
ステップ1: paypal-sdk-rest
を追加しますあなたのプロジェクトへの宝石。
これをGemfile
に追加します。
gem 'paypal-sdk-rest'
実行:
bundle install
ステップ2: APIキーを生成します。
PayPalと通信するためのAPIキーを取得するには、PayPalアカウントを作成する必要があります。そう:
- でアカウントを作成します(またはPayPalアカウントを使用します) https://developer.paypal.com/ 。
- まだアカウントにログインしている場合は、次の場所で2つのサンドボックスアカウントを作成します。 https://developer.paypal.com/developer/accounts/ :
- 個人(購入者アカウント)–これは支払いとサブスクリプションを行うためのテストで使用されます。
- ビジネス(マーチャントアカウント)–これは、探しているAPIキーを持つアプリケーションにリンクされます。それ以外に、このアカウントではすべてのトランザクションを追跡できます。
- でアプリを作成する https://developer.paypal.com/developer/applications 以前のビジネスサンドボックスアカウントを使用します。
- このステップの後、PayPalの2つのキーを受け取ります:
Client ID
およびSecret
。 config/application.yml
で、YOUR_CREDENTIAL_HERE
を置き換えますPAYPAL_CLIENT_ID
からおよびPAYPAL_CLIENT_SECRET
受け取ったばかりの鍵を使って。
ステップ3: PayPalモジュールを初期化します。
Stripeと同様に、application.yml
のキーを置き換える以外に、ENV
ですでに設定されているキーを使用できるようにPayPalモジュールを初期化する必要があります。変数。この目的のために、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
は、環境構成と2つのコールバック関数をプロパティとして持つオブジェクトです:createOrder
およびonApprove
。 PARAM2
PayPalボタンを付ける必要のあるHTML要素識別子を示します。
したがって、同じファイル内で、コメント付きのコードを置き換えます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取引
Stripeとは異なり、PayPalトランザクションのロジックは、フロントエンドからバックエンドに発信されるリクエストが増えるため、少し複雑になります。そのため、このセクションが存在します。 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: バックエンドが戻ってきたら、フォームを送信します。これは、バックエンドに対して行う3番目の要求です。
Stripeとは異なり、このプロセスではバックエンドに対して3つのリクエストが行われることに注意してください。また、それに応じて注文レコードのステータスを同期させます。
createOrder
コールバック:トランザクションが作成され、注文レコードも作成されます。したがって、それは 保留中 デフォルトとして状態。 onApprove
コールバック:トランザクションが実行され、注文は次のように設定されます paypal_executed 。 - 注文ページが送信されます:トランザクションはすでに実行されているため、何も変更されません。注文レコードはその状態を次のように変更します 有料 。
このプロセス全体を次のグラフで説明します。
PayPal取引 PayPal支払い
PayPalの支払いは、Stripe Chargesと同じロジックに従うため、1回限りのトランザクションを表しますが、前のセクションで説明したように、フローロジックが異なります。 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
で処理される支払いを作成および実行するための2つの新しいルートが作成されます。およびpaypal_execute_payment
コントローラメソッドを注文します。
ステップ2: PayPalサービスを作成します。
シングルトンクラスを追加するOrders::Paypal
で:app/services/orders/paypal.rb
。
このサービスには、最初に3つの責任があります。
create_payment
メソッドはPayPal::SDK::REST::Payment.new
を呼び出すことによって支払いを作成します。 A トークン 生成され、フロントエンドに返されます。 execute_payment
メソッドは、最初にPayPal::SDK::REST::Payment.find(payment_id)
を介して前に作成された支払いオブジェクトを見つけることによって支払いを実行します。を使用します Payment_id と同じ値を持つ引数として Charge_id 前のステップでorderオブジェクトに格納されます。その後、execute
と呼びます。特定の支払人をパラメーターとして使用する支払オブジェクト内。この支払人は、ユーザーが資格情報を提供し、ポップアップで支払い方法を選択した後、フロントエンドによって提供されます。 finish
メソッドは特定の順序で注文を検索します Charge_id で最近作成された注文のクエリ paypal_executed 状態。レコードが見つかった場合、それは支払い済みとしてマークされます。
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
へのリクエストを処理するための2つの新しいアクション(パブリックにする必要があります)を作成しますおよび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
の場合折り返し電話。最後のリクエストが成功を返した場合、サーバーに対して行われた3番目のリクエストである注文を送信することに注意してください。
createOrder
で関数ハンドラー、トークンを返します(バックエンドから取得)。 onApprove
でコールバック、バックエンドに渡される2つのプロパティがありますpaymentID
およびpayerID
。これらは、支払いを実行するために使用されます。
最後に、2つの空のelse
があることに注意してください。 PayPalサブスクリプションを追加する次のセクションの余地を残しているため、条項。
フロントエンドの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から提供されたプランIDを保存するために、商品paypal_plan_name
のフィールドを使用します。この場合、Stripeとは異なり、IDは選択せず、PayPalはこの値を返します。この値は、データベースで作成された最後の製品を更新するために使用されます。
サブスクリプションを作成する場合、customer
はありませんメソッドonApprove
のように、どのステップでも情報が必要です。おそらく、その基礎となる実装でこのリンケージを処理します。したがって、テーブルは同じままです。
ステップ1: PayPalAPIを使用してプランを作成します。
コマンド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
に2つの新しいルートを追加します。
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
でサブスクリプションを作成および実行するための関数をさらに2つ追加します。の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
を渡しますその属性の1つとして。その後、それを作成し、この最後のオブジェクトにトークンが設定されます。また、トークンをフロントエンドに返します。
execute_subscription
には、order
があります。前の呼び出しで作成されたレコード。その後、新しい契約を初期化し、この前のオブジェクトのトークンを設定して実行します。この最後のステップが正常に実行されると、注文ステータスは次のように設定されます。 paypal_executed 。そして今、フロントエンドに戻ります。これもorder.chager_id
に保存されています。
ステップ5: orders_controller
でサブスクリプションを作成および実行するためのアクションを追加します。
app/controllers/orders_controller.rb
を変更します。クラスの最上位で、最初に、次にコールバックを更新しますprepare_new_order
paypal_create_subscription
の前にも実行されますと呼ばれます:
class OrdersController また、同じファイルに2つのパブリック関数を追加して、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
を置き換えます次の関数を使用すると、2つの空の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');
サブスクリプションの作成と実行には、支払いに使用されるのと同様のロジックがあります。 1つの違いは、支払いを実行するとき、コールバック関数からのデータ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アプリケーションに統合できるようになります。簡潔にするためにこの記事では追加しなかった、改善できる点がたくさんあります。私は難易度の仮定に基づいてすべてを整理しました:
- より簡単に:
- リクエストがHTTPSを使用するように、トランスポート層セキュリティ(TLS)を使用します。
- PayPalとStripeの両方の本番環境構成を実装します。
- ユーザーが以前の注文の履歴にアクセスできるように、新しいページを追加します。
- 中:
- サブスクリプションの払い戻しまたはキャンセル。
- 未登録のユーザー支払いのソリューションを提供します。
- もっと強く:
- アカウントを削除して保持する方法を提供する トークン そして 顧客ID ユーザーが戻ってきたい場合。ただし、一定の日数が経過したら、このデータを削除して、アプリケーションがPCIに準拠するようにします。
- サーバー側でPayPalバージョン2APIに移行します( https://developer.paypal.com/docs/api/payments/v2/ )このチュートリアルで使用したgem paypal-sdk-rest 、バージョン2のベータ版しかないため、慎重に使用できます( https://github.com/paypal/PayPal-Ruby-SDK/tree/2.0-beta )。
- べき等の要求を含めます。
また、Stripeをフロントエンドに統合するもう1つの方法であるStripeCheckout要素について読むことをお勧めします。このチュートリアルで使用したStripeElementsとは異なり、Stripe Checkoutは、ユーザーがクレジットカード情報を入力するか、Google Pay / Apple Payで支払うことを選択するボタン(PayPalと同様)をクリックするとポップアップを開きます。 https://stripe.com/docs/web 。
2番目の推奨事項は、両方のペイメントゲートウェイのセキュリティページです。
最後に、この記事を読んでくれてありがとう!私もチェックできます このプロジェクトサンプルに使用されたGitHubプロジェクト 。そこに、私は追加しました rspec 開発中にもテストします。
基本を理解する
Stripeとは何ですか?どのように機能しますか?
Stripeは、インターネットを介して安全な支払いを実行するための個人または企業向けのソフトウェアを開発する会社です。
初心者のためのCSSチートシート
PayPalとStripeの違いは何ですか?
彼らは支払いを含むさまざまなアプリケーションを提供し、彼らのサービスを使用するためのさまざまな料金を持っています。
お支払い方法トークンとは何ですか?
支払いのトークン化は、ユーザーからの機密データを処理してトークンに変換するプロセスであるため、機密データの漏洩はありません。
PayPalは支払いゲートウェイまたはプロセッサーですか?
PayPalはゲートウェイではありませんが、完全なマーチャントソリューションです。ただし、Payflowと呼ばれる支払いゲートウェイを使用します。
Stripeは支払いゲートウェイまたはプロセッサーですか?
Stripeは、顧客のカードを処理する支払いゲートウェイです。