yamotonalds's blog

Webアプリケーション開発における技術メモが中心です。たまにWebサービス、興味を持ったデバイス、自作PCに関する話題もあるかも。Amazon好きなのでAmazon.co.jpアソシエイト使ってます。

ActiveMerchantでPayPalの定期支払い

PayPalの定期支払い(Recurring Payments)を実装したのだけれど嵌って大変だったのでメモ。

前提条件

  • activemerchant (1.34.0)

処理の流れ

公式ページを見るのが確実だった。

Integrating Recurring Payments | PayPal Developer

APIの呼び出し順としては、

  1. SetExpressCheckout
  2. GetExpressCheckoutDetails
  3. DoExpressCheckoutPayment
  4. CreateRecurringPaymentsProfile

となる。これをActiveMerchantのメソッドに置き換えると、

  1. setup_authorization
  2. details_for
  3. purchase
  4. recurring

となる。通常の決済では setup_purchase だったのが setup_authorization に変わっている点に注意。 また、パラメータも通常の決済とは異なる。

setup_response = gateway.setup_authorization(product.price * 100,
  ip: request.remote_ip,
  return_url: return_url,
  cancel_return_url: cancel_return_url,
  allow_note: false,
  no_shipping: true,
  items: [{
    name: product.name,
    number: product.id,
    quantity: 1,
    amount: product.price * 100,
  }],
  custom: product.id,
  billing_agreement: {
    type: "RecurringPayments",
    description: "商品名・商品の説明等"
  }
)

billing_agreementcustom というパラメータが増えている。customの方は後述のprofile_idと共に商品IDをDBに保存していれば不要。

recurring_response = gateway.recurring(product.price * 100, nil, {
    token: token,
    period: 'Day',
    frequency: 1,
    start_date: Time.zone.now + 1.days,
    description: '商品名・商品の説明等',
    initial_amount: product.price * 100,
    currency: "JPY",
    auto_bill_outstanding: true
})

tokenはsetup時に取得できるToken。初回支払いはpurchaseで行うのでstart_dateperiodに合わせてずらしている。descriptionは前述のbilling_agreementdescriptionと一致させなければならないので注意。 auto_bill_outstandingをtrueにすることで無期限の定期支払いにできる。

recurringが成功すると

recurring_response.params['profile_id']

でprofile_idを取得できる。この後説明するIPNではprofile_idを頼りにどの定期支払いに関する情報か判断するためDBに保存しておく。

定期支払いされた通知を受け取る

Profileを作成すると定期支払いが行われるようになるが、支払いが行われたことを知るための仕組みとしてIPNというものが用意されている。

PayPal側の設定

IPNを有効にするにはPayPalにログインして、「マイアカウント」→「個人設定」→「販売の設定」→「即時支払い通知の設定」をクリック。 通知先URLの入力と有効化のラジオボタンを選択する。これで支払い時にここで入力したURLに情報がPOSTされるようになる。

デフォルトではPOSTされるデータのエンコードがShift-JISになるようなのでUTF-8に変更しておく。設定場所は、「マイアカウント」→「個人設定」→「販売の設定」→「言語のエンコード」から「詳細オプション」をクリック。プルダウンを両方とも「UTF-8」にして保存する。

PayPalのSandboxで試す場合、Sandboxのアカウントでも同様に設定するのを忘れないこと。

通知が届いた後の処理

通知が届いたときの処理はActiveMerchantのドキュメントがほぼそのまま使える。

Class: ActiveMerchant::Billing::Integrations::Paypal::Notification

この例の

notify.item_id

で前述したcustomパラメータの値が、

notify.params['recurring_payment_id']

でprofile_idが取得できる。これらの値から支払いを特定し、購入処理を行う。 なお、定期支払い以外の支払い情報もIPNで通知されるようになっているので

notify.type == 'recurring_payment'

等で判定して処理を行う必要がある。

とりあえずこれで定期支払いは実装できたがWebで見つかるActiveMerchantの情報は古かったりpaypal_recurringというgemの情報だったりで混乱した(ただしpaypal_recurring gemのソースコードAPIのパラメータ周りで非常に参考になった)。 数ヶ月後の自分を含めた誰かの参考になるといいなぁ。

おまけ(IPN Simulator)

PayPalの開発者サイトにIPNのシミュレータがある。ただ定期支払いのIPNには対応していなかったりパラメータの自由度が低かったりするので参考程度に。

Payment Notifications | PayPal Developer

なお、このシミュレータの IPN handler URL に指定するURLは80番ポートでないとIPN送信が成功しないので注意が必要。

Railsで開発時のサーバのポートはpオプションで指定可能だが、Well-Knownポートを指定する場合はsudoが必要だった。 自分の場合はbundlerやrvmを使っていたので、

rvmsudo bundle exec rails server -p 80

というコマンドでサーバを起動する必要があった。