🅿️

PAY.JP で定期課金の再開する時の trial_end の設定方法

2024/07/03に公開

概要

ラブグラフエンジニアの熊谷です。
ラブグラフでは現在 PAY.JP の定期課金機能を利用して、サブスクリプションプランの運用をしております。
その中の「定期課金の再開」において、弊社では割と特異な利用方法(かもしれない使い方)をしているので、その方法などをまとめていきたいと思います。
よろしくお願いします。

対象読者

  • PAY.JPを使用してオンラインでの定期課金決済システムを管理または開発している方
  • サブスクリプションベースのサービスで、定期課金を効果的に管理しようと考えている開発者

定期課金再開(resume)の仕様を確認する

定期課金再開(resume)の仕様を確認します。
もちろん機能としては、停止もしくはキャンセル状態(status=canceled or paused)の定期課金を再開する挙動になります。

例1: 引数を指定しないで再開をする

subscription_id = "sub_567a1e44562932ec1a7682d746e0"

# 定期課金の再開( trial_end を指定しない )
subscription = PAYJP::Subscription.retrieve(subscription_id)
subscription.resume

puts subscription["status"]
>> "active"

定期課金ステータスは、 active になりつつ、決済もこのタイミングでおこなわれます。

弊社の定期課金では、「課金日(billing_day)が指定されていて、かつ日割り課金(prorate)が無効」の仕様のサービスになっていますので

課金日(billing_day)が指定されていて、かつ日割り課金(prorate)が無効の場合、 トライアル期間の終了日は次の課金日の日本時間午前9:00に自動調整されます。

再開のドキュメントにある上記の条件が適用されますので、引数に trial_end を指定することで、再開されるタイミングは次のサイクルの 9:00 に調整されます。

例2: 引数(trial_end)を指定して再開をする

trial_end に1分後を指定する
subscription_id = "sub_567a1e44562932ec1a7682d746e0"

# 定期課金の再開( trial_end を更新)
subscription = PAYJP::Subscription.retrieve(subscription_id)
subscription.resume(trial_end: 1.minute.since.to_i)

puts subscription["status"]
>> "trial"
puts Time.at(subscription["trial_end"])
>> "2024-05-01T09:00:00.000+09:00"

定期課金ステータスは、 trial 状態になり、実際の決済は次のサイクルの課金日の日本時間午前9:00 に調整されます。( 決済後にステータスは active になります)
→ 課金の再開は、次の課金サイクルの日本時間午前9:00に

このようにPAY.JPで定期課金の再開をおこなうとき、 trial_end の入力有無により、挙動が変わってきます。

ラブグラフの定期課金(再開時)でやろうとしていたこと

ここで改めて、弊社の定期課金の仕様をまとめます。

基本的な再開のケース

①すでに課金がおこなわれている状態で再開したとき、決済はおこなわれず、ステータスをアクティブに
②まだ課金がおこなわれていない状態で再開したとき、当月の料金を決済し、ステータスをアクティブに

上記2つを実現するために、基本的には例1の引数なしのコードを利用します。

課金日の深夜に再開がおこなわれるケースに対応する必要がある

例1のコードだけですと、課金日の9時より前の時刻の場合、日本時間では当月ですが、UTCでは先月(前サイクル)と扱われ、前サイクルとして再開がおこなわれてしまいます。

例: 日本時間の5月1日 7:00は、日本時間では5月だが、UTCではまだ4月な状態のときに、5月として再開させたい。もし仮に前サイクル中に再開すると、再開した深夜帯と、朝9:00 の2回決済がおこなわれることになってしまいます。

したがって、その間に再開する場合は、次のサイクルとして扱われて 9:00 のみに課金されるように処理したいと思います。

引数(trial_end)を入力して、次のサイクルから決済がおこなわれるようにする

例2の方法を使って、課金日で日本時間の 0:00 ~ 8:59 の間の場合は、課金日の日本時間9:00に再開されるように、 trial_end に適当な未来の時間(1分後など)を指定します。

これによって、課金日の 0:00 ~ 8:59 に再開をしたとき、「再開時」と「日本時間 9:00」の2度決済がされることを、防ぐことができました。

最終的なコードの書き方

ということで、最終的に上記パターンを網羅したコードはこのようになりました。

最終的な定期課金再開のコード
Payjp.api_key = "sk_test_c62fade9d045b54cd76d7036"
subscription_id = "sub_567a1e44562932ec1a7682d746e0"

# 課金日 && 0:00 ~ 8:59 の間か
is_early_hours_on_billing_date = is_billing_day? && is_early_time? # `is_billing_day?`, `is_early_time?` は別途定義してください

# 課金日の 0:00 ~ 8:59 のときは1分後、それ以外では nil を入力する
trial_end = is_early_hours_on_billing_date ? 1.minute.since.to_i : nil

subscription = Payjp::Subscription.retrieve(subscription_id)
subscription.resume(trial_end: trial_end)

「課金日かつ時間が0:00 ~ 8:59」のときのみ、未来の時間(この例では1分後)を入力することで、日本時間では課金日だけれども、PAY.JP上では前日のときに決済させず再開しつつ、それ以外の時間帯では即時決済をおこない再開できるようになっています。

これにて、再開時PAY.JPを利用してUTCを考慮した定期課金の再開が可能になりました。

まとめ

冒頭にも記載させていただきましたが、弊社の利用方法は少し特殊なサービス仕様になっているかもしれません。このやり方が標準的なアプローチかわからないところですが、少しでも参考になればと思っています。
最後まで読んでいただき、ありがとうございました。

REF

ラブグラフのエンジニアブログ

Discussion