android iOS java javascript 決済

Stripe + Javaでオーソリ(与信の確保)を実装する

投稿日:2020年6月30日

Stripeでチャリンチャリン、サービスを開発するエンジニアにとっては夢がありますよね。

例え自分で個人的に売るものが無かったとしても、Web決済システムを構築できるノウハウを持っておけば、公的な仕事で顧客に提案する際に有利に働くはずです。

以前、そんな夢を叶えてくれる「Stripe」を使ってテストWeb決済するまでを確認しました。

後はApple Pay、Google Payに本番申請、Webブラウザが運用ドメイン上でクレジットカード選択出来るようにして、StripeのLive(本番)キーを使えば実運用が出来るWeb決済システムの完成です。

夢の始まり・・・と言いたいところですが、本番で使用するには安全確保の為、もう一手間掛けたいところです。

「商品をユーザに譲渡した後、実際に決済をしようとしたらカードの上限額を超えているカードで決済が出来なかった。または決済はできたけど渡す商品の確保に失敗した。」

こんなケースは避けたいですよね。

こういったケースを防ぐ為に、カード会社に対して予定している決済金額を仮押さえする「オーソリ」 == 「カード会社に対する利用金額の確保(仮押さえ)」を今回は実装してみたいと思います。

オーソリ(与信確保)とは

実際に決済する前に、選択されたクレジットカードが支払い金額を払えるか事前にカード会社に確認、支払い金額を仮押さえすることが出来ます。

オーソリ状態は数日~数十日(カード会社によって異なる)維持することができ、商品を郵送し終わった後に決済することも出来ます。

支払い能力の有るクレジットカードなのか調べられるだけでなく、商品を渡すことが出来なかった時など、もし決済をすることが出来ない場合はオーソリをキャンセルすることで顧客のクレジットカードから無用な支払いを防ぐことができます。

サービス利用者さんとの金銭トラブルは避けたいですから、枕を高くして眠る為に開発の時点から施策を打っておきます。

実装するプログラムの動作イメージ

処理の流れのイメージはこんな感じです。
(順序分かり辛かったらすみません)

オンライン決済ではオーソリ状態から決済する処理を「キャプチャ」と言ったりします。StripeでもAPIレベルでcapture()が出てきます。

図を見るとなんか面倒そうだな、と思うじゃないですか?

ところがStripeを使って実際にプログラムを書いてみると、意外と簡単に実装出来てしまうんです。

実装開始

Stripe公式APIリファレンス(Java版)を見ながら書いていきます。

前回の記事からフロントエンド(HTML、JS)側は変更有りません。
バックエンドのJavaだけ変更します。愚直に書いて動作を確かめてみしょう。

実際の決済処理をオーソリに変更するには”capture”パラメータをfalseにするだけです。

Charge#create()で決済の替わりにオーソリをして、返って来たIDでCharge#capture(ID)することで決済が行われます。

    @RequestMapping(path = "/charge", produces = "application/json", method = { RequestMethod.POST })
    public ResponseEntity charge(@RequestBody ChargeRequest request) {

        ResponseEntity response = null;

        // ご自分のStripeプライベートキーを使用してください。
        Stripe.apiKey = "sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

        // 課金ID
        String chargeId = null;

        try {
            // 請求情報の準備
            Map<String, Object> chargeMap = new HashMap<String, Object>();
            chargeMap.put("amount", 500);
            chargeMap.put("description", "Tシャツ");
            chargeMap.put("currency", "jpy");
            chargeMap.put("source", request.stripeToken);

            // オーソリ(与信確保)指定フラグ(キャプチャ:決済はしない)
            chargeMap.put("capture", false);

            // オーソリ開始(カード会社に支払い金額の仮押さえが行われる)
            Charge authori = Charge.create(chargeMap);
            chargeId = authori.getId();
            System.out.println(authori);

            // 例外が発生せず、オーソリが通った状態。
            // 商品の確保、ユーザへの返却準備処理を行います。

            // オーソリした課金IDで決済(キャプチャ)
            Charge charge = Charge.retrieve(chargeId);
            charge.capture();
            System.out.println(charge);

            response = ResponseEntity.ok().build();
        } catch (StripeException e) {
            // 何か問題が発生した場合はオーソリ状態をキャンセル
            Map<String, Object> refundMap = new HashMap<String, Object>();
            refundMap.put("charge", chargeId);

            Refund refund;
            try {
                // オーソリに対するRefundは = オーソリキャンセルになる。
                refund = Refund.create(refundMap);
                System.out.println(refund);
            } catch (StripeException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();

            response = ResponseEntity.status(400).build();
        }

        return response;
    }

動確用の実装完了です。

動作確認

前回記事のフロントエンドからPayボタンを押して動作を確認してみます。

以下Eclipseコンソールにダンプした、オーソリ時の戻り値Chargeインスタンス。
capturedがfalseになっています。まだ決済されていません。

クレジットカード会社に対して利用金額を押さえただけの状態です。

<com.stripe.model.Charge@456381243 id=ch_1GxxxxxxxxxxxxxxxxxxxxhpR> JSON: {

  (snip)

  "captured": false,

  (snip)

次に決済(Charge#capture())時の戻り値Chargeインスタンス。capturedがtrueになっています。
このタイミングでカード会社と決済が正常終了したことが分かります。

<com.stripe.model.Charge@992525769 id=ch_1GxxxxxxxxxxxxxxxxxxxxhpR> JSON: {

  (snip)

  "captured": true,

  (snip)

stripe.comにブラウザアクセスしてどのように決済されたかダッシュボードを確認してみます。

オーソリ(承認された支払い)の後に決済(キャプチャされた支払い)をしていることが分かります。(Stripeテストキーなので実際にお金の流れは発生していません)

もしオーソリや決済に失敗した場合は例外が発生してRefund(払い戻し)をし、その時点で処理を止めることが出来ます。

カード会社がオーソリ機能を用意してくれていること、Stripeがそれを使う機能を具備していることで、支払ってくれないカードの為に商品を用意する必要が無いことが分かりました。

まとめ

  • カード会社には利用額を仮押さえする「オーソリ」という機能がある。
  • オーソリを使えば利用者との無用なトラブルを回避できる。
  • Stripeでオーソリするには決済メソッド、Charge#create()のMapパラメータにcapture=falseを設定するだけ。

余談:Stripeサポートのホスピタリティは高い

2020/06初頭、Chrome83がリリースされたタイミングでChromeからStripe経由でGooglePayが使えなくなる障害が発生しました。(6/11頃にChromeマイナーアップデートが出て復旧されています)

世界中のStripeを使ったシステムがこの影響を受け、私の開発、運営するサービスも影響を受けました。

その時Googleサポート、Stripeサポート両方に対応依頼を出しましたが、原因となったGoogle、とばっちりを受けたStripeのユーザ対応の丁寧さの差は歴然でした。

Stripeのサポートについて話題に出されているサイトも多いですが、サポート対応の品質がかなり高いんですよね。

懇切丁寧に、礼節を持って対応をしてくれました。
3.6%の手数料以外払ってないんですけどね(-_-;

日本法人があるのもすばらしいですね。私はStripeの回し者ではありませんが、

「B2Cで個人決済するシステムでは今後もStripeを採用したい」

そう思わせる事案でした。PCI-DSSに準拠するほどの予算が無いプロジェクトでは、Stripe採用は選択肢の一つとして一考する価値が十分にあると思っています。

-android, iOS, java, javascript, 決済
-, , ,

執筆者:

関連記事

B2BスマホアプリをGooglePlay、AppStoreに公開することを安易にお勧め出来ない7つの理由とその対策

商材の性質やシーンに応じてスマホアプリをGooglePlayやAppleStoreのようなストアに公開することがマイナスに働くこともあります。 商材として価値の有る電子データをお持ちの商社さんとアプリ …

プロパティ値変更を監視できるJavaScript、TypeScriptオブジェクトを作る

let taro= new Person(“yamada taro”, 25, “teacher”);taro.age = 26; こんなコードが有った …

Spring&JSPの検証環境を作る

2019年現在、オワコン風潮の強いJSPですが使っているプロジェクトもまだまだあり、枯れた技術を好む官公庁系のプロジェクトでは根強いシェアを誇っています。実装検証をする為に環境を作る機会があったりする …

ブラウザでRSA暗号化したデータをサーバで復号する(Angular + JSEncrypt、Spring MVC)【前編】

セキュリティ的にクリティカルなデータをクライアントブラウザで暗号化保存するようにしてみます。 通信経路はHTTPSで暗号化されていてもスマホに重要なデータが平文で残っていたら珠に傷です。 目次1 環境 …

JavaでRSA暗号を使う際にCRYPTREC暗号リストに足元をすくわれる可能性を回避する

標準的な暗号しか使わないケースでもJavaでRSAを使う時はBouncyCastleを入れておいた方が無難、という話です。 “ECB”という文字列がプログラム中にあると監査に引 …

 

shingo.nakanishi
 

東京在勤、1977年生まれ、IT職歴2n年、生涯技術者として楽しく生きることを目指しています。デスマに負けず健康第一。