ActiveMerchantでPayPalの定期支払い
PayPalの定期支払い(Recurring Payments)を実装したのだけれど嵌って大変だったのでメモ。
前提条件
- activemerchant (1.34.0)
処理の流れ
公式ページを見るのが確実だった。
Integrating Recurring Payments | PayPal Developer
APIの呼び出し順としては、
- SetExpressCheckout
- GetExpressCheckoutDetails
- DoExpressCheckoutPayment
- CreateRecurringPaymentsProfile
となる。これをActiveMerchantのメソッドに置き換えると、
- setup_authorization
- details_for
- purchase
- 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_agreement と custom というパラメータが増えている。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_dateはperiodに合わせてずらしている。descriptionは前述のbilling_agreementのdescriptionと一致させなければならないので注意。 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
というコマンドでサーバを起動する必要があった。