スポンサーリンク/Sponsored Link

【2019年旧記事】8月にアップデートしたSquareオンライン決済を実装しました。(PHP)

受験料お支払い画面
ニュースホームページ作成
スポンサーリンク/Sponsored Link
スポンサーリンク/Sponsored Link

本記事の実装は廃止されたため、アップデート記事をご覧ください

2019,年8月に本記事を投稿しておりましたが、本記事で実装したものは、2022年10月末で廃止されたため、現在は新しいAPIにアップデートして運用しています。

アップデート内容については、次の記事を参照ください。

現時点では、上記記事の実装が有効です。本記事この下にある実装をしても、支払い受付できません。

以下は、2019年当時の記事を残しています。


当校では、毎週土曜・日曜に資格試験を実施しています。(日曜日は実施しない週もあります)

近隣校ではまったく扱っていない試験なども多数実施しており、埼玉県内はもとより東京都、神奈川県、さらには埼玉県にお引っ越し予定の方が事前に北海道からお申し込みされた事例まであります。

そんなわけで、受験料のお支払いがスマホから簡単にできるシステムが必須なのです。

スポンサーリンク/Sponsored Link

手数料が安くて、入金が速くて、安全なオンライン決済はないものか……

当店は長らくこの目的で、PayPalビジネスのオンライン決済を使ってきましたが、教室の受講生様から教えていただいて、このたび「Square」決済を導入しました。

よく、AirペイCoineyなどと比べられるSquare。レジアプリもあり、店頭決済ももちろんできるのですが、
この種の決済サービスで、オンライン決済用のAPIがあるのは、たぶんSquareだけですね。

導入・テスト・実稼働がひととおり進みましたので、記事にしてみることにしました。

Squareのお申し込みは、こちらのリンクから行っていただくと当店からの紹介扱いとなり、手数料が10万円分無料になります。

スポンサーリンク/Sponsored Link

アメリカ発の新興決済サービス・Square

Squareについては、Wikipediaに次のようにまとめられています。

Square, Inc. | Wikipedia

固定費を安くし、イヤホンジャックに差すタイプの独特のカードリーダーを提供して、従来カード決済が難しかった小規模事業者や移動販売業者、固定店舗を持たない事業者を中心に一気に広まったサービス、ということのようです。

日本でのSquareサービス概要

店頭決済にはカードリーダーを購入

Squareリーダー

リーダーは7,980円で購入する必要があります。他の同様なサービスのカードリーダーが軒並み2万円近くかかるのに比べて、非常に安い印象です。

消費増税に伴う国のキャッシュレス補助金を活用すると、無料で入手できます。

リーダー以外の固定費がかからない

  • 月額利用料: 無料
  • 振込手数料: 無料
  • POSレジアプリのインストール: 無料
  • 払い戻し手数料: 無料
  • チャージバック手数料: 無料
  • アカウントの無効化: 無料

店頭決済以外にさまざまな決済方法が

店頭決済のほかに、次のような決済方法が標準で使用できます。

  • 請求書をメールで送って決済
  • 自動継続課金
  • ブラウザ上で決済
  • APIで決済を自分のサイトやアプリに組み込み

決済手数料

  • 店頭・請求書決済 3.25% (JCB 3.95%)
  • その他いろんな方法の決済 3.75%(JCB 3.95%)
  • API決済 3.60%(JCB 3.95%)

翌営業日の入金も可能な入金サイクル

登録している銀行口座によって、サイクルが異なります。

三井住友銀行・みずほ銀行
→翌営業日入金
0:00 から23:59(日本時間)までの決済分が、決済日の翌営業日に入金されます。

その他の銀行
→水曜日締め・金曜日入金
毎週木曜日 0:00 から翌週水曜日 23:59 までのカード決済額が、翌週金曜日に入金されます。

当店の場合、直近のご予約など入るため、三井住友銀行を登録して翌営業日に入金を受けています。

Coineyなどと比べて入金が大変早く、助かっています。

スポンサーリンク/Sponsored Link

Square API決済の概要

Squareのオンライン決済の概要は次のとおりです。

対応ブランド
VISA Master AMEX
※JCB Diners Discoverは店頭決済はできますが、API決済はできません

決済手数料
オンラインAPI決済 3.6%

デベロッパーポータルサイトが、通常の加盟店画面と別に存在し、ここにすべての開発用リソースが集中されています。

Square Developer Portal

スポンサーリンク/Sponsored Link

API決済の流れ

実際に当店で実装したAPI決済の流れをご紹介します。

Square PHP SDKをインストール

サーバーにSquare PHP SDKをインストールします。composerを使用します。

インストール方法はGitHubのReadme.mdを参照してください。

カード情報を入力→「nonce」を生成

受験者様がカード情報を入力する画面はこのようになっています。

受験料お支払いページ
(クレジットカード)

下記の内容で、受験料の決済を行います。 ご確認の上、カード情報を入力し、一番下の支払いボタンを押して決済してください。

お支払いの詳細

受験希望日
2019/08/31 18:00~
受験科目1
MOS2016 Word スペシャリスト(¥100)
受験科目2
MOS2016 Excel スペシャリスト(¥100)
決済合計金額 ¥200
※カード情報は、決済サービス「Square」のサーバーに直接送信されます。
当教室にはSquareより、決済の確認のためカード番号の下4桁、カード種別、有効期限、郵便番号のみが提供されます。

クレジットカード番号
有効期限
セキュリティコード
郵便番号
ボタン ¥200を支払う
(金額はテスト用のため少額になっています。実際の受験料とは異なります)

カード情報は、当店サーバーでなくSquareサーバーが直接受信するようになっています。次の開発者ページのコードを利用します。

チュートリアル:Square PaymentsをWebサイトに統合する | Square Developers

コード内のAccess Token/Location IDは、Square登録後にDeveloper Portalから確認できます。

<head>
---略
<!-- link to the SqPaymentForm library -->
	<script type="text/javascript" src="https://js.squareup.com/v2/paymentform">
	</script>
<!-- link to the local SqPaymentForm initialization -->
	<script type="text/javascript" src="Scripts/mysqpaymentform.js">
	</script>
<!-- link to the local custom styles for SqPaymentForm -->
	<link rel="stylesheet" type="text/css" href="css/mysqpaymentform.css">
</head>
<body>
 ---略
<p>※カード情報は、決済サービス「Square」のサーバーに直接送信されます。<br>
当教室にはSquareより、決済の確認のためカード番号の下4桁、カード種別、有効期限、郵便番号のみが提供されます。</p>
<?php
/* Payment section */
$sandboxmode = false;

// Autoload SDK package for composer based installations
require_once('bin/vendor/autoload.php');
if($sandboxmode == false){
  $accessToken = '*****Access Token******';
  $locationId = '*****Location ID*****';
} else {
  $accessToken = '****Sandbox Access Token****';
  $locationId = '****Sandbox Location ID**********';
}
?>
<!-- Square form -->
    <div id="form-container">
      <div id="sq-ccbox">
        <form id="nonce-form" novalidate action="/form_certification/payment_exec_creditcard.php?ordercode=<?php echo $ordercode;?>" method="post">
          <fieldset>
          クレジットカード番号
            <div id="sq-card-number"></div>
            <div class="third">
          有効期限<div id="sq-expiration-date"></div>
            </div>
            <div class="third">
          <span class="small">セキュリティコード</span><div id="sq-cvv"></div>
            </div>
            <div class="third">
          郵便番号<div id="sq-postal-code"></div>
            </div>
          </fieldset>
          <button id="sq-creditcard" class="button-credit-card" onclick="onGetCardNonce(event)"><?php echo money_format( "%n", 【受験料を計算するコード】);?>を支払う</button>
          <!--
            After a nonce is generated it will be assigned to this hidden input field.
          -->
          <input type="hidden" id="card-nonce" name="nonce">
        </form>
      </div> <!-- end #sq-ccbox -->
     </div> <!-- end #form-container -->
<!-- Square form -->

 

このように、スッカラカンの<div>を配置しておいて、Javascriptを実行します。applicationIDは、Square Developer Portalより入手します。

// Set the application ID
//const applicationId = "sandbox-sq*****"; //sandbox
const applicationId = "sq******"; //real


// onGetCardNonce is triggered when the "Pay $1.00" button is clicked
function onGetCardNonce(event) {
// Don't submit the form until SqPaymentForm returns with a nonce
event.preventDefault();
// Request a nonce from the SqPaymentForm object
paymentForm.requestCardNonce();
}

// Create and initialize a payment form object
const paymentForm = new SqPaymentForm({
// Initialize the payment form elements
applicationId: applicationId,
inputClass: 'sq-input',

// Customize the CSS for SqPaymentForm iframe elements
inputStyles: [{
    fontSize: '16px',
    lineHeight: '24px',
    padding: '16px',
    placeholderColor: '#a0a0a0',
    backgroundColor: 'transparent',
}],

// Initialize the credit card placeholders
cardNumber: {
    elementId: 'sq-card-number',
    placeholder: 'カード番号'
},
cvv: {
    elementId: 'sq-cvv',
    placeholder: 'CVV'
},
expirationDate: {
    elementId: 'sq-expiration-date',
    placeholder: 'MM/YY'
},
postalCode: {
    elementId: 'sq-postal-code',
    placeholder: '郵便番号'
},

// SqPaymentForm callback functions
callbacks: {
    /*
    * callback function: cardNonceResponseReceived
    * Triggered when: SqPaymentForm completes a card nonce request
    */
    cardNonceResponseReceived: function (errors, nonce, cardData) {
    if (errors) {
        // Log errors from nonce generation to the browser developer console.
        console.error('Encountered errors:');
        errors.forEach(function (error) {
            console.error('  ' + error.message);
        });
        alert('正しく入力されていません。内容をご確認ください。');
        return;
    }

    document.getElementById('card-nonce').value = nonce;
    document.getElementById('nonce-form').submit();
    }
}
});

 

Javascriptで生成されたInput要素に正しくカード番号が入ると、”nonce”という一意のIDが生成され、これのみが<button>クリック時にPOSTされる、という仕組みになっています。

取得したnonceを使用して決済実行

この”nonce”を取得できたら、支払いをユーザーが許諾した、という意味になりますので、以後、”nonce”がカード情報と同じ働きをし、決済が実行できます。

以下のコードは、PaymentsAPIのサンプル を手本にして作成しています。

  $nonce = $_POST['nonce'];   <---フォームからnonceを受け取り
// Autoload SDK package for composer based installations
require_once('bin/vendor/autoload.php');
【受験料読み出しモジュールをロード】
    if(empty($_SERVER['HTTPS'])){
        $hostname = 'http://'.$_SERVER["HTTP_HOST"];
      } else {
        $hostname = 'https://'.$_SERVER["HTTP_HOST"];
      }
    $returnbase = $hostname.'/form_certification/';
if($sandboxmode == true){
  $accessToken = '*****AccessToken****';
} else {
  $accessToken = '****Sandbox AccessToken****';
}

# setup authorization
$api_config = new \SquareConnect\Configuration();
$api_config->setHost("https://connect.squareup.com");
$api_config->setAccessToken($accessToken);
$api_client = new \SquareConnect\ApiClient($api_config);
# create an instance of the Transaction API class
$payments_api = new \SquareConnect\Api\PaymentsApi($api_client);

$request_body = array (
    "source_id" => $nonce,
    "amount_money" => array (
        "amount" => 【受験料合計を計算】,
        "currency" => "JPY"
    ),
    "buyer_email_address" => $data_user['email'],
    "note" => "連絡先 {【申し込み時メールアドレス】} / ordercode {【申し込みID】}",
    "idempotency_key" => uniqid()
);
unset($transactionId);
try {
    $result = $payments_api->createPayment($request_body);
} catch (\SquareConnect\ApiException $e) {
  header("Location:{$returnbase}/【支払キャンセル表示モジュールへ】);
}
if($result['payment']){
    header("Location:{$returnbase}/【支払完了モジュールへ】");
} else {
  header("Location:{$returnbase}/【支払キャンセル表示モジュールへ】");
}
?>

 

最後の if($result….. のくだりは、サンプルコードにない部分です。
これは、API決済で使えないJCBのカードが、サンプルコードを正常に通り抜けて「正常決済」と判定してしまったりすることへの対処です。

決済が正常であれば $result[‘payment’]が存在し、そうでなければ$result[‘Error’]が存在する。両方存在することはないのだそうです。それで、このようなコードにしております。

おそらく、カード番号自体がvalidであれば、nonceが正常に発行されてしまい、なおかつ、エラーがexceptionとしてではなく、$result[‘Error’]として返されるのだと思います。
例えば「残高不足」 などのエラーも、この方法でしかトラップできないと思われます。
exceptionは、createPaymentのリクエスト自体のエラーや、例えばセキュリティコード間違いなどのみ発生するようです。

詳しくは、 Square加盟店コミュニティ で質問し回答いただいた件ですので、加盟店の方はコミュニティで検索してご覧ください。

コーディング上の注意点

実際にやってみて、よくよく考えたら、例えば

「200円を支払う」というボタン表示でクリックさせて、実際には例えば20,000円を決済できてしまうのです。

PayPalやLINE PayのAPIも実装していますが、これらのAPIは、

金額指定して決済予約→同じ金額でしか決済実行できない

という構造です。

LINE Payオンライン決済を実装しました | キュリオステーション志木店のブログ

これに比べると、SquareのAPIはなんともアバウトで、実装側の良心に任されているというべきでしょうか。

ですので、お客様に表示する金額と、決済する金額が違ってしまわないように注意してください。違ってもエラーはでませんが、過剰または過小な請求が発生してしまいます。

2019年8月にSDKがアップデートしているので注意が必要

この記事を書いている最中の2019年8月に、APIがアップデートしました。

8月15日のアップデート内容をご覧ください。

従来使用されてきた transaction APIが「非推奨」となり、PaymentsAPIが推奨されたことをうけ、このアップデートでSDKもPaymentsAPIに対応しました。

上記のコードも、これをうけて急ぎ改修したものです。

2019/8/15以前に一度Square PHP SDKをインストールした方も、再度インストールする必要があります。そうしないと、上記のコードはエラーとなります。

スポンサーリンク/Sponsored Link

ご紹介扱いで手数料10万円分が無料に

Squareのお申し込みは、こちらのリンクから行っていただくと当店からの紹介扱いとなり、手数料が10万円分無料になります。

パソコン教室・キュリオステーション志木店からのお知らせ
レッスンはオンラインで受講できます

パソコン教室・キュリオステーション志木店では、オンラインでの在宅レッスンを実施しております。
教室の全コースがオンラインで受講可能。実際にインストラクターがご対応いたします。
1時間の無料体験レッスンはいつでも予約できます。詳しくは公式ページをご覧ください。

キュリオステーション志木店運営をフォローする
スポンサーリンク/Sponsored Link

コメント

タイトルとURLをコピーしました