皆さん、こんにちは。Misocaチームの @yusuke_kokubo です。
Active Merchantというgemをご存知でしょうか? Misocaはクラウド上で請求書をつくって送れるサービスです。請求書はお金を支払ってもらうためにつくるものなので、支払いもWeb上でできたら便利ですよね。 そこでMisocaには請求書に支払い機能を持たせられる「Misocaペイメント」という機能があります。 これはActiveMerchantによって実現されています。
本記事ではActiveMerchantの使い方として一番ポピュラーで簡単なPayPal支払いをご紹介したいと思います。
(PayPalについての基本的な知識は持っている、という前提で書きます。IPNって何?という方はまずはこちらをご覧ください。 即時支払い通知(IPN) - PayPal)
ここでは PaypalExpressGateway
というActiveMerchantの中のPayPal用モジュールを使って簡単なRailsアプリケーションを実装するためのステップを紹介します。
事前準備
sandboxアカウントを作成
まずはテスト用にPayPalのdeveloperアカウントを作成します。 https://developer.paypal.com/
さらに「Create Account」というボタンを押してsandbox用のテストアカウントを作成します。 typeはBUSINESSを選んでください。
作成すると、profileからAPI credentialsを確認できるようになります。 この情報がPayPalで支払先として設定するマーチャント(加盟店、お金を受け取る側)になります。
Railsアプリケーションのサンプル
gem install
Gemfile
に
gem 'activemerchant' gem 'offsite_payments'
と書いてください。
ちなみに offsite_payments
というのはActiveMerchantからRails依存の処理を抽出したgemらしいです。
(ハッキリしたことはわかってない)
routes.rb
こんな感じで書きます。実際にはアプリケーション用の注文IDなど、必要に応じてパラメータを付加してください。
scope path: 'payments', module: 'payments' do get 'new' => 'paypal_express#new', as: :paypal_payment get 'cancel' => 'paypal_express#cancel', as: :paypal_cancel get 'purchase' => 'paypal_express#purchase', as: :paypal_purchase get 'complete' => 'paypal_express#complete', as: :paypal_complete post 'notify' => 'paypal_express#ipn', as: :paypal_ipn end
view
PayPalの支払画面にリダイレクトして戻ってくるだけの流れなのでこれといった画面はありません。 支払い完了後の画面とキャンセルで戻ってきたときの画面があればじゅうぶんです。
app/views/payments/complete.html.erb
<header>
<h1>支払完了</h1>
</header>
<div class="main">
<p>支払が完了しました</p>
</div>
app/views/payments/cancel.html.erb
<header>
<h1>キャンセル</h1>
</header>
<div class="main">
<p>キャンセルしました</p>
</div>
controller
app/controllers/payments/paypal_express_controller.rb
サンプルとして最小限必要な処理はこんな感じです。 金額や明細(件名、数量)などは実際のアプリケーションに応じて変更してください。
基本的な処理の流れは
new
でPayPalの支払画面へ遷移purchase
で購入処理をして支払完了画面へ遷移ipn
でIPNを受け取って処理
となっています。
注意点としてIPNはPayPal側からのアクセスになるため、localhost:3000
のようなアドレスを指定するとIPNを受け取れません。
そのためにはngrokなどのツールを使ってポートフォワーディングする必要があります。
ngrokについては前回記事を参照してください。 tech.misoca.jp
module Payments class PaypalExpressController < ApplicationController AMOUNT_SAMPLE = 10000 ### PayPalの支払画面に遷移するために必要な情報を取得して ### 支払画面にリダイレクトする def new # 支払画面に飛ぶために必要な情報を取得する response = gateway.setup_purchase( AMOUNT_SAMPLE, ip: request.remote_ip, return_url: paypal_purchase_url, # PayPalで支払い処理後に戻るURL cancel_return_url: paypal_cancel_url, # PayPalでキャンセル処理後に戻るURL items: [ { name: "a subject", # 件名 quantity: 1, # 数量 amount: AMOUNT_SAMPLE # 支払い金額 }]) # ここでreview: falseに設定するとPayPal側で「今すぐ支払う」というボタン名に変わる # trueにすると「同意して支払う」となる # ボタン文言が変わるだけでそれ以外の違いは一切ない redirect_to gateway.redirect_url_for(response.token, review: false) end ### PayPalの支払画面で手続き後にアプリケーションに戻ってくるので ### 購入処理をする def purchase # details_forで金額や支払い先などの情報が取得できるので # 確認画面を表示したりする時に使う # 本記事では確認画面の表示はスキップする detail = gateway.details_for(params[:token]) # 購入処理 response = gateway.purchase( AMOUNT_SAMPLE, ip: request.remote_ip, token: params[:token], payer_id: params[:PayerID], notify_url: paypal_ipn_url # IPNを受け取るURL # localhostだとPayPalからアクセスできないので # 開発時にはngrokなどを使う ) if response.success? redirect_to paypal_complete_path else logger.error 'purchase failed.' end end def complete;render 'payments/complete';end def cancel;render 'payments/cancel';end # IPNを受け取ったときの処理 def ipn response = OffsitePayments::Integrations::Paypal::Notification.new(request.raw_post).extend(PaypalNotification) # 対象となる支払いをVERIFYしている unless response.acknowledge logger.error 'invalid ipn' render nothing: true, status: :bad_request end # 支払い金額が意図した金額になっているのか念のため確認 if response.completed?(AMOUNT_SAMPLE) logger.info 'completed' elsif response.refunded?(AMOUNT_SAMPLE) logger.info 'refunded' else logger.error 'failed' end # HTTPステータス204を返すとPayPal側で決済処理完了として扱われる render nothing: true end private def gateway ActiveMerchant::Billing.PaypalExpressGateway.new( login: '[sandbox accountのUsername]', password: '[sandbox accountのPassword]', signature: '[sandbox accountのSignature]' ) end end module PaypalNotification def completed?(amount) complete? && amount == gross.to_i end def refunded?(amount) status == 'Refunded' && (0 - amount) == gross.to_i end end end
def gateway
の中で、PayPalのAPIを呼び出すために事前につくったsandboxアカウントのAPI credentialsを埋めてください。
実行結果の確認
ngrokを立ち上げます。
./ngrok http 3000
https://xxxxx.ngrok.io/new
へアクセス(xxxxxの箇所はランダム)
うまく動けば、PayPal sandbox環境の支払い画面に遷移します。
URLのドメインが www.sandbox.paypal.com
となっていることが確認できると思います。
適当に支払い処理をしてください。 ローカルの画面に戻ってきたタイミングでIPNが飛んできたのもログから確認できると思います。
PayPalで確認
https://developer.paypal.com/ で結果を見てましょう。 sandboxアカウントを選んで「Notifications」をクリックすると結果が表示されます。
行を選択すると支払いの内容を確認できます。
Productionでの動作
development
で動かした場合はsandboxに接続に行くようになっています。
production
で動かせば本番のPayPalに接続されるように自動的に切り替わります。
もちろん本番環境ではsandboxアカウントのAPI credentialsは使えないので本物のビジネスアカウントをご使用ください。
まとめ
如何でしたでしょうか。 ActiveMerchantを使えば支払い機能を簡単に作成できます。
PayPal以外でも様々な決済に対応していますし、未対応の決済代行会社のAPIでも 自分でモジュールを書けば対応できます。 機会があれば、そういった上級編もご紹介してみたいと思います。