[レジなし無人販売冷蔵庫] AmazonPayを使用してQRコードで支払いしてみました(Sandboxのみ)

2020.12.27

1 はじめに

CX事業本部の平内(SIN)です。

Amazon Web Services ブログでは、「レジなし無人販売冷蔵庫を構築についての記事」が公開されています。
レジなし無人販売冷蔵庫を構築できる、This is my Smart Cooler プログラムを公開しました

こちらでは、「お客様自らがレジなし無人販売冷蔵庫を迅速に構築し学習や体験ができる This is my Smart Cooler プログラムを発表します。」ということで、そのレシピがGithubで公開されています。
レジ無し無人販売冷蔵庫 構築レシピ

「これを真似てみたい」ということで、ここまで作業を進めています。

今回は、AmazonPayによる支払いについて確認してみました。

2 Amazon Pay API SDK (Node.js)

AmazonPayでは、Node.jsでSDKが提供されており、これを使用することで簡単に支払い処理を記述できます。

$ npm install @amazonpay/amazon-pay-api-sdk-nodejs

SDKでは、クライアントは、AmazonPayClientWebStoreClient、及び、InStoreClientの3種類が利用可能ですが、今回使用したのは、InStoreClientです。

const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs');

const testPayClient = new Client.AmazonPayClient(config);
// -or-
const testPayClient = new Client.WebStoreClient(config);
// -or-
const testPayClient = new Client.InStoreClient(config);

手順としては以下の2つだけです。

  • 1 Merchant Scan QRコードを渡して、chargePermissionIdを取得
  • 2 Charge chargePermissionIdと価格等を渡して決済する

また、APIは、秘密鍵と公開鍵のペアーで認証され、キーペアは、AmazonPayのインテグレーションセントラルから作成可能でです。

3 コード

SDKを使用して、決済を行うコードです。

下記では、クライアントを生成した後、「1. Merchant Scan」と「2. Charge」の2つの処理を一気に行っています。

require('date-utils');
const Client = require('@amazonpay/amazon-pay-api-sdk-nodejs');

// 日付文字列の生成
function dateStr(){
	const dt = new Date()
	return dt.toFormat("YYYYMMDDHH24MISS");
}

// クライアントの生成(キーペアで初期化)
function InStoreClient(publicKeyId, privateKey, sandbox){
	const fs = require('fs');
	const config = {
		'publicKeyId' : publicKeyId,
		'privateKey' : fs.readFileSync(privateKey),
		'region' : 'jp',
		'sandbox' : sandbox
	};
	return new Client.InStoreClient(config);
}

// QRコードを渡して、chargePermissionIdを取得
async function Scan(client, scanData){
	const payload = {
		scanData: scanData,
		scanReferenceId: 'scanReferId'+dateStr(),
		merchantCOE: 'JP',
		ledgerCurrency: 'JPY',
	};
	result = await client.apiCall({
		method: 'POST',
		urlFragment: 'in-store/merchantScan',
		payload: payload,
	})
	return JSON.parse(result.body).chargePermissionId
}

// chargePermissionIdと価格等を渡して決済する
async function Charge(client, chargePermissionId, amount, merchantNote, merchantStoerName, merchantOrderId){
	const payload = {
		chargePermissionId  : chargePermissionId,
		chargeReferenceId : "chargeRefId" + dateStr(),
		chargeTotal : {
		  currencyCode : 'JPY',
		  amount : amount,
		},
		metadata : {
			merchantNote : merchantNote,
			communicationContext : {
				merchantStoreName : merchantStoerName,
				merchantOrderId : merchantOrderId
			}
		}
	};
	result = await client.apiCall({
		method: 'POST',
		urlFragment: 'in-store/charge',
		payload: payload,
	})
	return JSON.parse(result.body)
}

async function main(){

	const publicKeyId = "AFWJFRXXXXXXXXX6KD3IXFPC";
	const privateKey = './private.pem';
	const sandbox = "true";
	
	try{
		// InstoreClient
		const client = InStoreClient(publicKeyId, privateKey, sandbox);

		// 1. Merchant Scan
		const scanData = "AZXXXXXXXXXXXXX6b";
		const chargePermissionId = await Scan(client, scanData)
		console.log(`chargePermissionId: ${chargePermissionId}`)

		// 2. Charge
		const amount = 100;
		const merchantNote = "note";
		const merchantStoerName = "Classmethod";
		const merchantOrderId = "CM_" + dateStr();
		const result = await Charge(client, chargePermissionId, amount, merchantNote, merchantStoerName, merchantOrderId);
		console.log(`chargeStatus: ${result.chargeStatus.state} chargeId: ${result.chargeId}`)
	
	}catch(error){
		console.log(`ERROR: ${error.body}`)
	}
}

main()

決済に成功すると、以下のようなログが表示されます。

chargePermissionId: S03-0761296-9042492
chargeStatus: Completed chargeId: S03-0761296-9042492-C060188

また、AmazonPayの「取引管理」で決済された内容が確認できます。

4 SDKのエラー処理

上記のコードで、間違ったscanDataを渡すと、以下のようなエラーとなります。これにより、読み取ったQRコードが、正規のAmazonPayのものかどうかが判定できます。

ERROR: {"reasonCode":"InvalidParameterValue","message":"Invalid customer key [ABCDEFG]"}

既に決済の終わったchargePermissionIdを使用して、Chargeを行おうとすると、以下のようなエラーとなります。

ERROR: {"reasonCode":"DuplicateRequest","message":"Request has already been processed for ChargePermissionId "}

また、無効な、chargePermissionIdも受け付けることはできません。

ERROR: {"reasonCode":"InvalidParameterValue","message":"[PARAMETER CONSTRAINT VIOLATION] charge.arg1.chargePermissionId is invalid. Actual value provided is S03-5337510-7601214123."}

5 最後に

QRコードを使用した、AmazonPayの実装は、至ってシンプルです。 QRコードを読み取る決済は、実装が比較的簡単と言えそうです。