GMO payment Gateway / リンクタイプ-Plus 導入

GMO Payment Gateway とは

>GMO Payment Gatewayは、日本を拠点とするオンライン決済サービスプロバイダーで、多様な決済手段（クレジットカード、コンビニ決済、電子マネーなど）を提供しています。
>
>企業や個人事業主が安全でスムーズな決済処理を導入できるよう、さまざまな支払いオプションやセキュリティ対策をサポートします。
>
>(ChatGPT)

GMOPaymentGatewayには4つの「接続方式」が存在する。

* (1) プロトコルタイプ 
  * 接続仕様に沿って、加盟店様にプログラムを開発して頂きます。 
  * HTTPS通信によるリクエスト／レスポンス型通信にてデータを受け渡します。 

* (2) リンクタイプ 
  * 弊社側で用意した決済用画面にリンク（画面遷移）する方式です。 
  * 決済用画面のデザインは、テンプレートファイルを編集することで変更可能です。 

* (3) リンクタイプ Plus 
  * 弊社側で用意した決済用画面にリンク（画面遷移）する方式です。 
  * 決済用画面のデザインは、管理画面から設定、またはURL作成時に指定可能です。 

* (4) モジュールタイプ 
  * 決済処理用のモジュール（プログラム）を加盟店様側のサーバに導入して頂きます。 
  * 通信処理部分についての開発を行う必要がありません。 

今回は「リンクタイプPlus」を使用することとして話を進めていく。

ダッシュボードから見ると、「その他」のタブの中に「リンクタイプPlus」メニューがある。

そのほかの画面でも少しわかりにくいところに「リンクタイプPlus」の選択肢が置かれていることが多い。(Linepay、PayPayなど各種決済サービスリストの一番下に「リンクタイプPlus」というメニューが別途置かれていたりなど。)

なお、リンクタイプPlusのドキュメントについてはすべてWeb上にしか存在しない。

(リンクタイプPlusが比較的新しいサービスなのか、その他のサービスはPDFが置かれている形式だったりする。もっとも、それも少しづつWebドキュメントに移植されているようであるが。)

以下、リンクタイプPlusのテスト方法について簡単に説明する。

ドキュメント(https://docs.mul-pay.jp/linkplus/payment/common)

<img src="data:image/png;base64," >

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990851/49a5a6ec-0675-ae1b-657e-7d3508748c91.png)


URLにも2種類あり、「パラメータ型」と「キー型」が存在するが、キー型は難しそうなので、今回はパラメータ型で実行する。

おおむね画像の通りなのだが、なにしろ細かいところが全く説明されていないので、説明する。（別箇所で説明されてはいるけど分かりにくいし繋がりづらい。）

早速テスト用URLを組み立てていく。

可変する部分を除けば、次のようなURLが出来上がる。

決済URL`https://stg.link.mul-pay.jp/v1/plus/${shopId}/checkout/${base64params}`

このうち、`${shopId}`はダッシュボード左上に表示されている「ショップID」のことだ。
(サイトIDではない)
ショップIDはそのまま埋め込めばいいが、末尾の`${base64params}`の方は少し特殊で、指定された手順で作った文字列を埋め込む必要がある。

こちらも一応ドキュメントに書かれてはいるが、非常にわかりづらい。（なにしろこちらはURLがここで作られるか自分で作らなければいけないのかすら分からないのだ。）

>### ハッシュ付き実行パラメータセットの生成方法
>リンクタイプ Plusの決済画面を呼び出すためには、取引の内容を示す各種パラメータ(決済金額や取引を特定するオーダーID等)一式が必要です。これらパラメータ一式を「実行パラメータセット」と呼びます。 実行パラメータセットはjson形式で表現しますが、リンクタイプ Plus決済URLに付与する際は、base64エンコード（URLSafe）を行い、パラメータ改ざんチェック用にハッシュを付与したハッシュ付き実行パラメータセット文字列にします。
>
>ハッシュ付き実行パラメータセットの導出方法を以下に示します。
>[公式]

<img src="data:image/png;base64," >

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990851/1d4ada96-1952-c2b5-ffc8-7533b936832b.png)


## パラメータ文字列作成

まずは`json`文中の各パラメータについて。`configId`は、ダッシュボード中の「その他＞リンクタイプPlus＞設定」から見える、「設定ID」のことだ。

設定IDには決済画面のデザイン設定や各種決済方法のパラメータなどを保存できるので、呼び出す「設定ID(=configID)」によってパラメータなどを変えることができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990851/a006201e-16d2-9e77-5d8f-a15eed6d306d.png)

`transaction`パラメータの中にはその取引固有の情報を入れる。

`OrderID`はその取引に固有のIDであり、ほかの取引と重複することのないユニークな値をこちらで設定する必要がある。

>### オーダーID
>加盟店様が取引を識別するために使用するIDです。一度使用した値を再度使用する事はできませんので、注文番号等の変更ができない値を直接設定しないでください。
>設定可能な文字は「半角英数字と"-"（ハイフン）」です。
>
>https://docs.mul-pay.jp/service/glossary#orderid

### ショップパスワード
もうひとつ、「ショップパスワード」という項目が処理の中で使用される。

ショップパスワードは、ダッシュボード中の「ショップ管理＞ショップパスワード」より、確認することができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990851/17a7cb3b-1cd8-ad83-5aa6-1b89538162c1.png)

`json`が完成したら、手順に沿って文字列を作成していく。

1. `json`文字列をbase64エンコード(UTF-8)する。エンコード後の文字列を「α」とする。
2. αにショップパスワードを結合する(α+ショップパスワード)。この文字列を「β」とする。
3. 「β」文字列のSHA256ハッシュを算出する。ハッシュ文字列を「γ」とする。
4. 「α」と「γ」を「.」(ドット)で結合する(α + '.' + γ)。この文字列を「ε」とする。
5. 「ε」が、`${base64params}`となる。

この処理を書いたと思しきコードが、ダッシュボード中の「コードサンプル」に存在する。（「決済」ドロップダウンを「リンクタイプPlus」に合わせると出てくるが、非常にわかりづらい。）

コードサンプルだと、Java,PHP,Rubyの3言語での例が出ているが、ここでは`NodeJS`での例を紹介する。

JSON
```json:.params.json
{
  "configid": "t3",
  "transaction": {
    "OrderID": "O001",
    "Amount": "1"
  }
}
```

JS
```js:linkTypePlusUrlGenerator.js
import * as fs from 'fs'
import crypto from 'crypto'

// Base64エンコードする関数
function encodeBase64(input) {
  // Bufferを使って文字列をバイナリデータに変換し、Base64エンコードする
  return Buffer.from(input).toString('base64')
}

// SHA-256ハッシュを計算する関数
function calculateSHA256(input) {
  return crypto.createHash('sha256') // SHA-256アルゴリズムを指定
    .update(input)        // 入力データを渡す
    .digest('hex')       // ハッシュ値を16進数（hex）で出力
}

// const shopId = '...'
// const shopPassword = '...'
const baseUrl = `https://stg.link.mul-pay.jp/v1/plus/${shopId}/checkout/`

// json文字列をbase64エンコード
const json_string = fs.readFileSync('.params.json', 'utf8')
const alpha = encodeBase64(json_string)
// β = α+ショップパスワード
const beta = alpha + shopPassword
// γ = SHA256(β)
const gamma = calculateSHA256(beta)
// ε = alpha + "." + gamma
const epsilon = alpha + "." + gamma

console.log(baseUrl + epsilon)
```

shopId、shopPasswordにそれぞれ値を入力し、jsonファイルを配置し、nodeでjsを実行する。

出来上がったURLにアクセスすると、リンクタイプPlusの決済選択画面が表示されるはず。

## 決済結果判定

決済結果を受け取る画面をURLで指定するような表記があるが(retUrl,completeUrl,cancelUrl...)...、リンクタイプPlusの場合は別らしい

>### 必ず決済結果を取得するにはどうすればいいですか？
> 
>【結果通知プログラム】というマルチペイメントサービスから加盟店様システムへ
>非同期で決済結果を通知する機能のご利用を検討ください。
>
>結果通知プログラムは、決済状態の変化を弊社システムが検知すると
>決済結果返却とは別のタイミングで加盟店様システムへ決済状況を通知する機能です。
>
>＜リンクタイプ、リンクタイプPlusご利用の場合＞
>
>リンクタイプの性質上、エンドユーザーが決済途中の画面でブラウザを閉じてしまう、
>通信状況が悪く途中で通信できなくなる等の理由で加盟店様サイトへ結果が通知されない事があります。
>
>結果通知プログラムを利用することで、上記のようにお客様が決済完了後に加盟店様サイトへ
>戻れない事態が生じても、決済状況を取得することが可能となります。
>
>■結果通知プラグラムのご利用について
>
>新たなご契約は不要です。
>
>結果通知プログラムの利用には、加盟店様にて受信用プログラムとURLを準備いただく必要があります。
>　　　
>SSL証明書の種類によっては、結果通知プログラムが正常に受取れない場合がございます。
>
>弊社で動作保証をしているSSL証明書については以下に記載のQ＆Aを確認のうえ導入する証明書の決定をお願いいたします。
>
>https://mp-faq.gmo-pg.com/s/article/F00262

数は少ないが、Web上の記事を見ても、決済結果の判定は「結果通知プログラム」を利用するのが安全といえそうだ。

## 参考リンク

ドキュメント
* https://docs.mul-pay.jp/service/doclist
* https://docs.mul-pay.jp/linkplus/overview
* https://docs.mul-pay.jp/linkplus/payment/common
* https://docs.mul-pay.jp/linkplus/payment/paymentapi
* https://docs.mul-pay.jp/linkplus/payment/common#3-0

Qiita
* https://qiita.com/wanna_be_neet/items/9835212bea2f615bef2a
* https://qiita.com/You_name_is_YU/items/a114c015bdc61ba0ccae
* https://qiita.com/You_name_is_YU/items/5617bec05204d0f26518
* https://qiita.com/You_name_is_YU/items/3466888c85d4895465ee
* https://qiita.com/horikeso/items/c8e8a5ec623d94cc18cd
* https://qiita.com/You_name_is_YU/items/7e1664ce39c8ba5c04c0