Open6
stripe メモ
特にstripe connectを使った設計の備忘録を残しておく
入金処理について
- 自動入金とマニュアル入金があるが(platform、connected accountどちらも)、締め概念を作りたい場合現状マニュアルで設計するしかない
- ちなみにplatformは自動、connected accountはマニュアルという組み合わせは問題ないらしい(逆は仕組み上問題があるぽい、理由はちょっと忘れてしまった)
- 決済手段自体を導入するのに比べてかなり工数かかるイメージなのでマニュアルで実装する場合は相応の工期を取るようにする
- 大枠どのように設計するか
-
- stripeのbalance transactionから金額を計算するパターン
- connected accountと紐づいてるbalance transactionを対象分取得(API or Sigmaで)して計算
- 入金額がアカウントの残高以下であれば入金処理を実行する(パターン2の場合も同様)
- メリット:ざっくりと(charge - platform_earning) - (refund + dispute - platform_earning_refund)とかで計算できる
- デメリット:内部的にこの決済は含めないみたいな条件がある場合balance transactionだけだと集計できない
-
- 内部データから金額を計算するパターン
- charge(payment intent使う場合は紐づくもの)、refund、dispute、balance transaction、application feeあたりはオンライン/バッチ処理組み合わせて取っときたい
- 入金バッチのタイミングで対象のchargeやrefundやdisputeテーブルから入金金額を計算
- balance transactionの中でchargeなどは比較的紐付けやすいがfeeなどをどう紐付けるか迷った、結果的にfeeは内部で決済時にカラムに入れることにしたので結局balance transactionもいらないのでは?となってきてる
- メリデメはパターン1の逆
-
- 最初から考慮しときたいこと
- chargeだけじゃなくrefundやdispute(やtopupも使う予定あれば)が発生することを前提に金額計算の処理を作っておく
- refundやdisputeで発生する損害をplatformとconnected accountのどちらが負担するのか規約含めて早めに決める
- 例えばrefundの負担をどちらに持たせるかで↓のような入金額の差が発生する(¥100の商品、application fee10%、stripe fee3%、縦が時系列)
connected account | platform | stripe fee |
---|---|---|
¥90 | ¥10 | (¥3) |
connected accountの損失による返金の場合↓ | ||
¥0(netで-¥10の損失) | ¥0 | (¥3) |
platformの損失による返金の場合↓ | ||
¥0 | ¥0(netで-¥3の損失) | (¥3) |
=> ということは入金処理をchargeとrefundの単純足し合わせで実装すると、 | ||
A. connected account側の損失の時は、(charge(ex. ¥100) - platform_earning(ex. ¥10)) - refund(ex. ¥100) 、これはconnected accountから見ると-¥10になる |
||
※ 負の値になるので入金額全体も負になり入金処理ができない可能性もあり | ||
B. platformの損失の時は、(charge(ex. ¥100) - platform_earning(ex. ¥10)) - (refund(ex. ¥100) - platform_earning_refund(ex. ¥10)) 、これはconnected accountから見ると¥0になる |
- 発生したchargeやrefundのデータは内部的にどう管理するか
- 結果的にchargesテーブルを作ってSTIにしてcharges::stripe_chargeやcharges::stripe_refundみたいなtypeを作ることで一貫したインターフェースで操作できるような形にした(まだ運用にのせてないので今後変わるかも)
- 売り上げフローと発生するbalance transactionを把握しておく
- balance transaction側で必要とするデータのイメージを最初に持っておいた方が手戻りしない
- 売り上げフロー:https://stripe.com/docs/connect/destination-charges#flow-of-funds-app-fee
- payment intentを使う場合は紐づくchargeをキャプチャ後に取得する
- chargesと配列で取得できるが原則1つのchargeしか入ってこないとのこと(海外での決済の場合は複数
-
入金速度はキャプチャしてから+4日後に入金可能
-
キャプチャタイミングによって入金反映分が変わるのでちょっと気にしないといけないかも
-
入金額に最低金額は設定されてない
-
マイナス入金になりえる、入金と引き落としのどちらも対応してる必要あり
-
入金失敗した際に手動入金とかでリカバリできるようにしておく必要あり
-
支払いが拒否された後に5回以上リトライできないような仕組みにしたほうがいい
-
拒否理由
-
サブスクの場合支払い失敗のnotifyもしないといけない
stripe webhookのコード例 (rails)
class StripeEventHandler
def call
payload = request.body.read
event = Stripe::Event.construct_from(JSON.parse(payload, symbolize_names: true))
class = 'StripeEvent::' + event.type.tr('.', '_').camelize + 'Handler'
class.new.call(event)
rescue JSON::ParserError => e
render json: { status: 400, error: 'Invalid payload' }
rescue Stripe::SignatureVerificationError => e
render json: { status: 400, error: 'Invalid signature' }
end
end
module StripeEvent
class BalanceTransactionAvailableHandler
def call(event) # メソッドはcallだけを持つ
event&.data&.object # => Balance Transaction Objectが取得できる
end
end
end
- transferのデータを取り込む理由
- chargeに紐付けてtransferを取り込むことで、reverse_transferを意図的に発生させることが可能になる、reverse_transferをすることで例えばconnected accountから一部のお金を回収したいユースケースに対応することが簡単に実現できる
入金について追記
- dispute処理に関してplatformから手数料を徴収される
- そのため仮にconnected account側に非がある場合手数料を請求する必要あり
- chargeを発行するとしたら => https://stripe.com/docs/connect/account-debits#連結アカウントに請求する
- transfer_reversalを使うという方法もありそう(ロジックが複雑になりそう、だが手数料がかからない)
- そのため仮にconnected account側に非がある場合手数料を請求する必要あり
- 入金処理自体に各種手数料がかかる
- https://stripe.com/jp/connect/pricing
- connected accountが負担をする場合同様に請求処理が必要