Tech Racho エンジニアの「?」を「!」に。
  • 開発

ActiveMerchant を使ってPayPal Express Checkout の与信取得と回収機能を導入する

どうも、shibuso です。前回「PayPal のSandbox に挑んでみた」を書きましたが、今回はRuby のライブラリ「ActiveMerchant」を用いてPayPal Express Checkout に対応した大まかな流れをまとめてみたいと思います。GitHub にあるActiveMerchant のWiki からリンクが張られているCody Fauser - PayPal Express Payments with ActiveMerchant (以降Cody Fauser と呼びます)を参考にしました。順番も基本はこれと同じです。

注: Cody Fauserはその後閉鎖しました。

この記事を読むにあたって、前提条件としてある程度Rails が使えることと、PayPal Sandbox 環境が整っていることが求められます。また、今回の実装は即時課金を行うのとは少し違う「与信取得→後日回収」という実装を行なっていますが、こうしたPayPal の最低限の仕様理解も必要です。なお、PayPal の解説ページも所々説明で活用します。また、実装環境はRails 3.2.12, ActiveMerchant 1.31.1 です。

では始めましょう。まずActiveMerchant のgem を入れます、ここはActiveMerchant のReadme と同じです。続いてCody Fauser と同じくconfig/environments/development.rb にSandbox を使用するように指定します。

# config/environments/development.rb
config.after_initialize do
  ActiveMerchant::Billing::Base.mode = :test
end

更に日本円を扱う場合は、通貨を設定します。config/environment.rbに下記を記述しました。

# config/environment.rb
ActiveMerchant::Billing::PaypalExpressGateway.default_currency = "JPY"

続いてgateway の準備をします。Cody Fauser では使用するクラス内に記述していましたが、私は複数箇所で使用する想定だったのでモデルに書きました。ここで必要な情報は全てPayPal のSandbox で取得出来ます。

# app/models/paypal_transaction.rb
class PaypalTransaction < ActiveRecord::Base
  include ActiveMerchant::Billing

  # 省略

  def self.gateway
    @gateway ||= PaypalExpressGateway.new(
      :login => username,
      :password => password,
      :signature => signature
    )
  end
end

ここまでで準備完了です。以降の実装はPayPal とのやり取りが発生します。PayPal の解説ページの「STEP 2. 導入・ご利用方法(導入イメージ)」の図が大まかな動作順を表しています。ユーザから見たら以下の図ような流れになります。

実行順序

それではこれからA. SetExpressCheckout にあたる部分を実装します。この後は基本的にコントローラでの実装です。

# app/controllers/payment_controller.rb
def checkout

  # 省略

  setup_response = PaypalTransaction.gateway.setup_authorization(
    price,
    :ip                => request.remote_ip,
    :return_url        => url_for(:action => 'confirm', :only_path => false),
    :cancel_return_url => url_for(:action => 'cancel', :only_path => false),
    :items             => items
  )

  paypal_transaction.token = setup_response.token
  paypal_transaction.save!

  redirect_to PaypalTransaction.gateway.redirect_url_for(setup_response.token)
end

上記でprice は日本円を指定した場合、数値を100 倍する必要があるようです。return_url とcancel_return_url はそれぞれ用意して下さい。items には様々な情報が入ります。gem の中身を見ると確認できます、場所はactive_merchant/billing/gateways/paypal/paypal_common_api.rb のadd_payment_details_items_xml メソッドです。

redirect されるとユーザはしばらくPayPal の画面での処理になります。次にこちらに返ってくるのはPayPal 上でログインしたり支払いの意思を明確にした後です。呼ばれるのは先程return_url で指定したページなので、次はその実装についてです。

# app/controllers/payment_controller.rb
def confirm
  if params[:token].blank?
    # エラー処理
  end

  details_response = PaypalTransaction.gateway.details_for(params[:token])

  if !details_response.success?
    # エラー処理
  end

  # 省略
  # params[:token] と同じtoken を持つレコードを探す(先程token を保存したレコード)、無い場合はエラー処理

  paypal_transaction.payer_id = params[:PayerID]
  paypal_transaction.save!

  # details_response から必要な情報を修得
end

ここでは各種情報の確認や保存を行います。payer_id はしっかり保存しましょう。また、このコントローラに対応したビューでは支払いの最終確認を行うので、ユーザに確認してもらうために必要な情報を表示できるよう取得する必要があります。

この次、ユーザが確認ボタンを押した時に実行する処理が重要です。「与信取得→後日回収」を実装する場合は以下のようになります。

# app/controllers/payment_controller.rb
def complete

  # 省略
  # 各種エラーチェック等

  authorize = PaypalTransaction.gateway.authorize(
    price,
    :ip       => request.remote_ip,
    :payer_id => paypal_transaction[:payer_id],
    :token    => paypal_transaction[:token]
  )

  if !authorize.success?
    # エラー処理
  end

  paypal_transaction.authorization_id = authorize.authorization
  paypal_transaction.save!
end

Cody Fauser ではpurchase になっている部分がauthorize に変わっていることが確認できると思います。ここをauthorize にすることにより、即時課金ではなく与信取得状態となります。authorization_id は重要なのできちんと保存して下さい。

この後は、いつ与信を回収するかで実装が変わります。PayPal は3 日以内ですと残額が保証されているのでそのまま回収することができますが、それを過ぎると再与信する必要があります。状態によっては再与信の取得に失敗するので、それを想定した実装が必要になります。また、再与信が可能なのは1 回だけです。以下は回収するメソッドです。

# app/models/paypal_transaction.rb
def self.exec_capture

  # 省略

  if 前回与信した日から3 日以上経過していた場合
    reauthorize = PaypalTransaction.gateway.reauthorize(price, paypal_transaction.authorization_id)
    if !reauthorize.success?
      # エラー処理
    end
  end

  capture = PaypalTransaction.gateway.capture(price, paypal_transaction.authorization_id)
  if !capture.success?
    # エラー処理
  end
end

reauthorize で再与信取得となります。その後capture することにより回収完了です。

おまけとして、与信を取得したけれどキャンセルする場合は以下のような実装で可能です。

# app/models/paypal_transaction.rb
def self.exec_reject

  # 省略

  rejected = PaypalTransaction.gateway.void(paypal_transaction.authorization_id)

  if !rejected.success?
    # エラー処理
  end
end

void を実行することにより回収をキャンセルすることができます。PayPal のSandbox では「拒否」というステータスになります。

最後に。上記の実装は2013 年4 月現在で確認したものです。今後使用変更等で動作しなくなる可能性もあるので、その際は適宜修正して下さい。以上、PayPal Express Checkout の与信取得と回収機能の導入解説でした。

関連記事

PayPal のSandbox に挑んでみた


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。