SB Payment リンク型決済プラグイン¶
概要¶
SB Payment Service (SBPS) のリンク型クレジットカード決済をVendureに統合するプラグインです。
- リンク型決済: 加盟店サイトからSBPS決済画面へリダイレクト
- XML処理:
fast-xml-parserを使用した保守性の高い実装 - シミュレーションモード: APIキー未取得時でもテスト可能
機能¶
主要機能¶
- リンク型決済フロー
- 注文情報からSB Payment API用のXMLリクエストを生成
- SB Payment決済画面へのリダイレクトURL生成
-
決済完了後のコールバック処理
-
XML処理
fast-xml-parserを使用したXMLパース・生成iconv-liteを使用したUTF-8⇄Shift_JIS変換- SB Payment仕様(XML 1.0、Shift_JIS)に準拠
-
ハッシュ検証によるセキュリティ確保
-
シミュレーションモード
- APIキー未取得時でも動作確認可能
- 成功レスポンスをエミュレート
- テスト環境での開発を支援
設定¶
環境変数¶
以下の環境変数を設定してください:
# SB Payment API設定
SB_PAYMENT_MERCHANT_ID=your_merchant_id
SB_PAYMENT_SERVICE_ID=your_service_id
SB_PAYMENT_HASH_KEY=your_hash_key
# APIエンドポイント(オプション)
SB_PAYMENT_API_ENDPOINT=https://api.sbpayment.jp/test/
SB_PAYMENT_LINK_URL=https://api.sbpayment.jp/test/link/
# コールバックURL(オプション)
SB_PAYMENT_CALLBACK_URL=http://localhost:3005/sb-payment/callback
SB_PAYMENT_CANCEL_URL=http://localhost:3005/sb-payment/cancel
Vendure設定¶
apps/vendure-server/src/vendure-config.tsでプラグインを起動し、Vendureのplugins配列に登録します。SbPaymentLinkPlugin.initは環境変数を優先しつつ、未設定項目には開発用デフォルト値を与えます。
import { SbPaymentLinkPlugin } from '@ritsubi/plugins';
plugins: [
// 省略
SbPaymentLinkPlugin.init({
simulatorMode: IS_DEV || !process.env.SB_PAYMENT_MERCHANT_ID,
apiEndpoint: process.env.SB_PAYMENT_API_ENDPOINT,
linkUrl: process.env.SB_PAYMENT_LINK_URL,
merchantId: process.env.SB_PAYMENT_MERCHANT_ID,
serviceId: process.env.SB_PAYMENT_SERVICE_ID,
hashKey: process.env.SB_PAYMENT_HASH_KEY,
callbackUrl: process.env.SB_PAYMENT_CALLBACK_URL,
cancelUrl: process.env.SB_PAYMENT_CANCEL_URL,
}),
],
使用方法¶
決済フロー概要¶
SbPaymentLinkHandlerが注文データからXMLリクエストを生成し、SB Paymentに送信します。- レスポンスで受け取ったリダイレクトURLを
payment.metadata.public.redirectUrlとして返し、StorefrontはそのURLにリダイレクトします。 - 決済完了通知を
POST /sb-payment/callbackで受信し、SbPaymentLinkServiceが検証後に該当PaymentをSettledへ遷移させます。 - エラー・キャンセル時はSB
Payment側でユーザーを
cancelUrlに戻し、Vendure側ではログ記録のみ行います。
1. シミュレーションモード(APIキー未取得時)¶
環境変数が設定されていない場合、自動的にシミュレーションモードで動作します:
- 決済作成時に即座に成功レスポンスを返す
- 実際のSB Payment API呼び出しは行わない
- テスト用のトラッキングIDを生成し、
payment.metadata.simulator=trueを付与
2. 本番モード(APIキー取得後)¶
環境変数を設定すると、実際のSB Payment APIを使用します:
- 決済作成: 注文情報からXMLリクエストを生成し、SB Payment APIに送信
- リダイレクト: 生成されたリダイレクトURLを
payment.metadata.public.redirectUrlとしてStorefrontへ返却し、フロントエンドで遷移 - 決済完了: SB Paymentからのコールバックを受信し、注文を確定
3. コールバックエンドポイント¶
プラグインは以下のエンドポイントを提供します:
POST /sb-payment/callback: 決済完了コールバック(注文状態を更新)POST /sb-payment/cancel: 決済キャンセル通知(ログのみ)
実装構成¶
SbPaymentLinkService¶
- XML生成・送信、ハッシュ検証、コールバック処理を一元管理
RequestContextServiceを用いて管理APIコンテキストを生成し、OrderService.transitionPaymentToStateでPaymentをSettledへ遷移TransactionalConnectionでPaymentエンティティを取得し、SB Paymentレスポンスをpayment.metadata.sbPaymentResponseに保管
SbPaymentLinkHandler¶
- Vendureの
PaymentMethodHandlerを実装し、createPaymentでXMLを構築 - 返却する
metadata.public.redirectUrlはStorefront GraphQLから参照可能 cancelPayment/settlePaymentはシミュレーションモードを考慮しつつ即時成功を返す
SbPaymentCallbackController¶
POST /sb-payment/callbackと/cancelを提供- コールバック受信時に
SbPaymentLinkService.handleCallbackを呼び出し、決済結果を検証
決済コールバック処理¶
- 受信XML(Shift_JIS)をUTF-8へ変換し
fast-xml-parserでパース res_sps_hashcodeを使ってハッシュ検証res_tracking_idからPayment.transactionIdを特定し、対応する注文を読み込み- SB Paymentレスポンスを
payment.metadata.sbPaymentResponseへ保存 - まだ
Settledでない場合はOrderService.transitionPaymentToState(..., 'Settled')を呼び出し確定 - 成功時はHTTP 200、失敗時は400/500を返却
テスト¶
接続支援サイトでのテスト¶
SB Paymentの接続支援サイトを使用してテストできます:
- XMLリクエストの生成確認
- プラグインが生成するXMLリクエストを確認
-
ハッシュ値の計算が正しいか検証
-
エラーハンドリングの確認
- 不正なリクエストに対するエラー処理
- レスポンスのパース処理
シミュレーションモードでのテスト¶
APIキーがなくても、以下のテストが可能です:
// 決済作成テスト
const result = await paymentHandler.createPayment(ctx, order, amount, {}, {});
// シミュレーションモードでは即座に成功
expect(result.state).toBe(PaymentState.Authorized);
expect(result.metadata.simulator).toBe(true);
実装詳細¶
XML処理¶
fast-xml-parserとiconv-liteを使用してXMLを処理:
// XMLパース(Shift_JIS→UTF-8変換後)
const parser = new XMLParser({
ignoreAttributes: false,
attributeNamePrefix: '@_',
textNodeName: '#text',
parseAttributeValue: true,
trimValues: true,
});
// XML生成(UTF-8→Shift_JIS変換前)
const builder = new XMLBuilder({
ignoreAttributes: false,
attributeNamePrefix: '@_',
textNodeName: '#text',
format: true,
suppressEmptyNode: false,
});
// XML生成フロー
// 1. fast-xml-parserでUTF-8のXMLを生成
const xmlUtf8 = builder.build(data);
// 2. XML宣言を追加(Shift_JIS指定)
const xmlWithDeclaration = `<?xml version="1.0" encoding="Shift_JIS"?>\n${xmlUtf8}`;
// 3. iconv-liteでUTF-8→Shift_JIS変換
const xmlShiftJis = iconv
.encode(xmlWithDeclaration, 'Shift_JIS')
.toString('binary');
// XMLパースフロー
// 1. iconv-liteでShift_JIS→UTF-8変換
const xmlUtf8 = iconv.decode(buffer, 'Shift_JIS');
// 2. fast-xml-parserでパース
const data = parser.parse(xmlUtf8);
ハッシュ計算¶
SB Payment仕様に準拠したハッシュ計算:
private calculateHash(data: string): string {
return crypto.createHash('sha1')
.update(data, 'utf-8')
.digest('hex');
}
エラーハンドリング¶
- XMLパースエラー
- API通信エラー
- ハッシュ検証エラー
- 決済失敗時の処理
トラブルシューティング¶
よくある問題¶
- ハッシュ検証エラー
- ハッシュキーが正しく設定されているか確認
-
ハッシュ計算用文字列の順序を確認
-
コールバックが受信されない
- コールバックURLが正しく設定されているか確認
-
ファイアウォール設定を確認
-
シミュレーションモードが有効にならない
- 環境変数
SB_PAYMENT_MERCHANT_IDが設定されていないか確認 - プラグインの初期化オプションを確認
参考資料¶
技術的な注意事項¶
文字コード変換¶
SB Payment APIはXML 1.0形式でShift_JISエンコーディングを要求します:
- XML生成: UTF-8(JavaScript内部)→ Shift_JIS(API送信)
- XML解析: Shift_JIS(API受信)→ UTF-8(JavaScript内部)
- XML宣言:
<?xml version="1.0" encoding="Shift_JIS"?>を明示的に指定
実装のポイント¶
fast-xml-parserはUTF-8で動作するため、Shift_JIS変換が必要iconv-liteでUTF-8⇄Shift_JIS変換を実現し、XML宣言は<?xml version="1.0" encoding="Shift_JIS"?>を手動追加- HTTPリクエスト/レスポンスは
Content-Type: application/xml; charset=Shift_JISを指定 - Vendure側では
payment.metadata.public.redirectUrlでStorefront公開情報と、payment.metadata.sbPaymentResponseで内部監査情報を分離