■目的
毎日決済が成功しているかを朝 9:30ごろに確認するため、その時間までにその日の決済が行われるようにしてほしい。
10/18 21:00:00 に決済されるものを -> 10/18 09:03 に決済されるようにしたい。
■補足
Stripeは基準の時間がUTC時間に準じて操作となるため、日本時間0:00〜08:59に決済される取引については、月初の決済日の場合、日に応じて決済日が変更される可能性があります。
https://tech.stmn.co.jp/entry/2021/01/28/093349
そのため、0:00〜08:59 に決済されるようにする候補がなくなり、9時過ぎに変更するということになりました。
■始めに考えたこと
無料期間を設定し、無料期間の終了のタイミングを決済日の9:03 に設定する方法を検討しました。
■問題点
しかし、この場合、カスタマーポータルをお客様が開いた時にプランが無料期間中という表示がなされます。
また、更新した時点で0円のインボイスが発生し履歴に残ります。
これでは、サブスクリプションを契約しているクライアント様に状況を説明する必要があり、不採用となりました。
■そこで考えた結果
Cronを使って、対象のサブスクリプションに対して、
'billing_cycle_anchor' => 'now'
を利用することを検討しました。
対象のサブスクリプションに対して、「今更新して!」という指示を与えるということです。
指定の時間 (毎日9:03頃)にこのプログラムを走らせるのは、人間業ではないなと考えていたところ、Cron を思い出しました。
たまたま、契約しているサーバーがX Server ということもあり、
特にお客様が何か新しいサービスを契約する必要がなかったのも非常に良かったです。
*cronとは、簡単にいうと自動で指定の時間に指定のプログラムを実行すること
https://e-words.jp/w/cron.html
■やり方思いついたけど、そのほかにも検討材料たくさんあります。
・対象のサブスクリプションの判定方法
対象のサブスクリプションの判定について非常にデリケートに行いました。
Stripeのサブスクリプションを探す方法で
$useSubscriptionAll = $stripe->subscriptions->all
というものがありますが、
この$useSubscriptionAll の中に、対象ではないサブスクリプションが絶対に入ってはいけないため、allの条件を調べました。
すると、
current_period_end{gte、lte} を利用すればできそうということがわかりました。
gte は その時間以降に決済されるもの
lteは その時間までに決済されるもの
ということとなります。
https://stripe.com/docs/api/subscriptions/list
対象のサブスクリプションを抽出するために。。。
$useCurrentDay_Start = strtotime(date("Y/m/d 09:04:00"));
$useCurrentDay_End = strtotime(date("Y/m/d 23:59:59"));
$useSubscriptionAll = $stripe->subscriptions->all(
['limit' => 100,
'status' => 'active',
'current_period_end' => [
'gte' => $useCurrentDay_Start,
'lte' => $useCurrentDay_End
]
]
);
9:03以前に決済されたものを含むと1日に2回決済されるため 9:04 としています。
この取得した配列の中から、さらに条件分岐を行います。
一番は、10/31 に決済されたものを11/30 に決済しないようにするということです。
これは、10/31 の次の決済日は、11/30 ですが、11/30 に 更新プログラムを実行した場合、次の決済日は、12/30 となります。
そのため、一旦はサブスクリプションの作成日と決済日が一致しないものについては除外するようにしました。
条件分岐後取得したサブスクリプションに対して、
$usesubscriptions = \Stripe\Subscription::update($useArrayId, [
'billing_cycle_anchor' => 'now',
'proration_behavior' => 'none',
’metadata' => ['payment_time' => 'updated’]
]);
更新すると自動的に2回目以降の決済が9:03頃に実行されるようになりました。
*更新を実行したサブスクリプションに対して、metadata でフラグを立てています。
■またまた問題点が発生 (3回目以降の決済について)
本プログラムを実装してから気づいたんですが、
Stripeのサブスクリプションというのは、
決済時間(9:03)に、インボイスの下書き作成 ->
1時間後 (10:03) に請求書が確定 ->
請求書が確定後に登録済み支払い方法で決済確定
となります。
そのため、上記のままでは、3回目以降の決済が10:03 になるという事態が発生しました。。。
3回目以降の決済が9:03 になるように最初の決済を8:03 に変更するということも検討しましたが、時差の関係で、あまり前向きに進めるべきではない・・・
ということで、今度は、webhookを利用して、3回目以降の9:03 の下書きのインボイスが作成されたタイミングで、強制的に支払いを実行するプログラムを実装することにしました。
$stripe->invoices->pay
を利用することで、指定のインボイスを即時決済させることが可能です。
これで、3回目以降の支払いについても、
請求書の下書きが作成されたタイミングで、(invoice.created)を受信するwebhookを作成し、
取得したイベントから、3回目以降の決済であるかどうかの条件分岐を行い、対象のインボイスIdを取得し、
stripe->invoices->pay (対象のインボイスId)
で実装が出来ました。
■終わりに
決済時間を変更するにあたり無料期間を設定するとその履歴が残るということは盲点でした。
そのため、今回はcronを利用し、指定の時間に更新プログラムを実行するようにしました。
気づけてよかったです。
Stripeを通じてクライアント様のお役に立ててよかったです。
Stripeは状況に応じて、クライアント様のご都合に合わせて、
かなり自由に設定できるのは間違いなく、まだまだ発見がありそうです。
とても奥が深いStripe。
これからもたくさんプログラムを書いてお役に立っていこう。
長くなりましたがありがとうございました。