gasで頑張る人はいないのか、AIに聞いても中々手こずったの同じことしようとしている人向けに公開
実際に作ったサイトはhttps://x.gd/Ppm2Z
上記の管理用スプレッドシートhttps://x.gd/XSFmu
PAY.JPの決済方法
const url = 'https://api.pay.jp/v1/charges';
const options = {
method: 'post',
headers: {
Authorization: 'Basic ' + Utilities.base64Encode(paymentKeys.payjpSecret + ':'),
'Content-Type': 'application/x-www-form-urlencoded'
},
payload: {
amount: String(orderData.total),
currency: 'jpy',
card: orderData.paymentToken,
description: '商品購入'
},
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
const result = JSON.parse(response.getContentText());
if (result.error) throw new Error(result.error.message);
stripeのカード決済
const customer = createStripeCustomer(orderData.email);
if (customer.error) throw new Error(customer.error.message);
const stripeUrl = 'https://api.stripe.com/v1/payment_intents';
const base64Key = Utilities.base64Encode(paymentKeys.stripeSecret + ':');
const webAppUrl = ScriptApp.getService().getUrl();
const attachResponse = UrlFetchApp.fetch(`https://api.stripe.com/v1/payment_methods/${orderData.paymentToken}/attach`, {
method: 'post',
headers: {
Authorization: 'Basic ' + base64Key,
'Content-Type': 'application/x-www-form-urlencoded'
},
payload: { customer: customer.id }
});
if (JSON.parse(attachResponse.getContentText()).error) {
throw new Error('PaymentMethodのアタッチに失敗しました');
}
const intentOptions = {
method: 'post',
headers: {
Authorization: 'Basic ' + base64Key,
'Content-Type': 'application/x-www-form-urlencoded'
},
payload: {
amount: String(orderData.total),
currency: 'jpy',
customer: customer.id,
payment_method: orderData.paymentToken,
confirm: 'true',
return_url: webAppUrl + '',
setup_future_usage: 'on_session',
'metadata[order_id]': orderNumber.toString()
},
muteHttpExceptions: true
};
const intentResponse = UrlFetchApp.fetch(stripeUrl, intentOptions);
const intentResult = JSON.parse(intentResponse.getContentText());
if (intentResult.error) throw new Error(intentResult.error.message);
stripeの銀行振込
const customer = createStripeCustomer(orderData.email);
if (customer.error) throw new Error(customer.error.message);
const stripeUrl = 'https://api.stripe.com/v1/payment_intents';
const base64Key = Utilities.base64Encode(paymentKeys.stripeSecret + ':');
const webAppUrl = ScriptApp.getService().getUrl();
// Create and confirm PaymentIntent in one step
const payload = {
amount: String(orderData.total),
currency: 'jpy',
customer: customer.id,
'payment_method_types[]': 'customer_balance',
'payment_method_data[type]': 'customer_balance',
'payment_method_options[customer_balance][funding_type]': 'bank_transfer',
'payment_method_options[customer_balance][bank_transfer][type]': 'jp_bank_transfer',
confirm: 'true',
return_url: webAppUrl + '',
'metadata[order_id]': orderNumber.toString()
};
const options = {
method: 'post',
headers: {
'Authorization': 'Basic ' + base64Key,
'Content-Type': 'application/x-www-form-urlencoded'
},
payload: payload,
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(stripeUrl, options);
let result;
try {
result = JSON.parse(response.getContentText());
} catch (e) {
console.log('Stripe APIレスポンス:', response.getContentText());
throw new Error('Stripe APIのレスポンスが不正です');
}
stripのコンビニ決済
const customer = createStripeCustomer(orderData.email);
if (customer.error) throw new Error(customer.error.message);
const stripeUrl = 'https://api.stripe.com/v1/payment_intents';
const base64Key = Utilities.base64Encode(paymentKeys.stripeSecret + ':');
const intentOptions = {
method: 'post',
headers: {
Authorization: 'Basic ' + base64Key,
'Content-Type': 'application/x-www-form-urlencoded'
},
payload: {
amount: String(orderData.total),
currency: 'jpy',
customer: customer.id,
'payment_method_types[]': 'konbini',
payment_method: orderData.paymentToken,
'metadata[order_id]': orderNumber.toString()
},
muteHttpExceptions: true
};
const intentResponse = UrlFetchApp.fetch(stripeUrl, intentOptions);
const intentResult = JSON.parse(intentResponse.getContentText());
if (intentResult.error) throw new Error(intentResult.error.message);
// コンビニ決済の詳細を取得
let konbiniDetails = null;
if (intentResult.next_action && intentResult.next_action.konbini_display_details) {
konbiniDetails = intentResult.next_action.konbini_display_details;
}
// モックデータを使用してコンビニ支払い情報を表示
const mockKonbiniDetails = {
convenience_store: 'lawson',
expires_at: Math.floor(Date.now() / 1000) + 86400, // 24時間後
payment_code: '1234567890',
receipt_number: '1234-5678',
hosted_instructions_url: 'https://pay.stripe.com/test_instructions'
};
konbiniDetails = konbiniDetails || mockKonbiniDetails
stripeのコンビニ決済はテスト環境ではコンビニ決済の詳細を返してくれないためモックを使っています。