Stripe: 商品を作成 (Stripe: Create Product)
この工程は、Stripe 上に商品オブジェクトを作成します。商品に設定した価格は商品価格オブジェクトとして保存されます。
Configs:共通設定
  • 工程名
  • メモ
Configs
  • C1: API シークレットキーを設定した認証設定 *
  • C2: 商品名 *#{EL}
  • C3: 商品説明#{EL}
  • C4: 通貨 *
  • C5: 単価(通貨の最小単位で指定。USD の場合はセント) *
  • C6-1C: サブ通貨 1
  • C6-1A: サブ通貨 1 の単価(通貨の最小単位で指定)
  • C6-2C: サブ通貨 2
  • C6-2A: サブ通貨 2 の単価(通貨の最小単位で指定)
  • C6-3C: サブ通貨 3
  • C6-3A: サブ通貨 3 の単価(通貨の最小単位で指定)
  • C6-4C: サブ通貨 4
  • C6-4A: サブ通貨 4 の単価(通貨の最小単位で指定)
  • C7: 商品オブジェクトの ID を保存するデータ項目
  • C8: 商品オブジェクト詳細ページの URL を保存するデータ項目
  • C9: 商品価格オブジェクトの ID を保存するデータ項目
  • C10: 商品価格オブジェクト詳細ページの URL を保存するデータ項目

Notes

  • Stripe の API シークレットキーを取得するには https://dashboard.stripe.com/apikeys を参照してください
  • 単価は通貨の最小単位で設定してください
    • 例えば、10 USD を請求するには、1000(1000 セント)と設定します
    • 詳細は Stripe のドキュメントを参照してください

Capture

See also

Script (click to open)
  • 下記のスクリプトを記述した XML ファイルをダウンロードできます
    • stripe-product-create.xml (C) Questetra, Inc. (MIT License)
    • Professional をご利用であればファイルの内容を改変することでオリジナルのアドオンとして活用できます


const STRIPE_API_VERSION = '2022-08-01';
const CURRENCY_OPTIONS_NUM = 4; // サブ通貨の最大設定数

main();

function main(){
    //// == Config Retrieving / 工程コンフィグの参照 ==
    const auth = configs.get('conf_Auth');
    const name = retrieveConfig('conf_Name', 'Product Name', true, 250);
    const description = retrieveConfig('conf_Description', 'Product Description', false, 250);
    const currency = configs.get('conf_Currency');
    const unitAmount = retrieveUnitAmount(configs.getObject('conf_UnitAmount'), 'Unit amount', true);
    const currencyOptions = retrieveCurrencyOptions(currency);
    const productIdDef = configs.getObject('conf_ProductId');
    const productUrlDef = configs.getObject('conf_ProductUrl');
    const priceIdDef = configs.getObject('conf_PriceId');
    const priceUrlDef = configs.getObject('conf_PriceUrl');

    //// == Calculating / 演算 ==
    const {productId, priceId} = createProduct(auth, name, description, currency, unitAmount, currencyOptions);

    //// == Data Updating / ワークフローデータへの代入 ==
    setData(productIdDef, productId);
    setData(productUrlDef, `https://dashboard.stripe.com/products/${productId}`);
    setData(priceIdDef, priceId);
    setData(priceUrlDef, `https://dashboard.stripe.com/prices/${priceId}`);
}

/**
  * config から設定値を読み出す。以下の場合はエラー
  * - 空文字列の場合
  * - 長さが maxLength を超える場合
  * @param {String} confName config 名
  * @param {String} label エラー出力用ラベル
  * @param {String} required 必須項目かどうか
  * @param {Number} maxLength 最大文字数
  * @return {String} value 設定値
  */
function retrieveConfig(confName, label, required, maxLength) {
    const value = configs.get(confName);
    if (required && value === '') {
        throw `${label} is blank.`;
    }
    if (value.length > maxLength) {
        throw `${label} must be at most ${maxLength} characters.`;
    }
    return value;
}

/**
  * スクリプトエンジンから商品単価を取得する
  * 商品単価として不正な場合はエラー
  * @param {DataDefinitionView} dataDef 商品単価が保存されているデータ項目
  * @param {String} label エラー出力用ラベル
  * @param {boolean} required 必須項目かどうか
  * @return {String} unitAmount 商品単価(非負整数)
  */
function retrieveUnitAmount(dataDef, label, required) {
    const maxAmount = 99999999;
    const bigDecimal = engine.findData(dataDef);
    if (bigDecimal === null) {
        if (required) {
            throw `${label} is blank.`;
        }
        return null; // 必須項目でない場合にのみ null を返す
    }
    let longValue;
    try {
        longValue = bigDecimal.longValueExact();
    } catch (e) {
        throw `${label} must be integer.`;
    }
    if (longValue < 0) {
        throw `${label} must not be negative.`;
    }
    if (longValue > maxAmount) {
        throw `${label} must be smaller than ${maxAmount + 1}.`;
    }
    return longValue.toString();
}

/**
  * config から通貨オプションの組を読み出し、Map に格納して返す。以下の場合はエラー
  * - 通貨は設定されているのに、単価のデータ項目が未選択
  * - 通貨が重複している
  * - 単価の値が不正
  * @return {Map<String, String>} metadataMap メタデータの Map
  */
function retrieveCurrencyOptions(mainCurrency) {
    const currencyOptions = new Map();
    for (let i = 0; i < CURRENCY_OPTIONS_NUM; i++) {
        const currency = configs.get(`conf_Opt${i+1}_Currency`);
        const unitAmountDef = configs.getObject(`conf_Opt${i+1}_UnitAmount`);
        if (currency === null || currency === '') {
            if (unitAmountDef === null) { // 通貨、単価がともに未設定の組は無視
                continue;
            }
            throw `Unit amount for sub-currency ${i+1} is set while sub-currency ${i+1} is not selected.`;
        }
        if (currency === mainCurrency || currencyOptions.has(currency)) { // 通貨の指定が重複
            throw `Currency ${currency.toUpperCase()} is set multiple times.`;
        }
        if (unitAmountDef === null) { // 単価のデータ項目が未選択
            throw `Unit amount for sub-currency ${i+1} is not set.`;
        }
        const unitAmount = retrieveUnitAmount(unitAmountDef, `Unit amount for sub-currency ${i+1}`, false);
        if (unitAmount !== null) { // 単価のデータ項目の値が空の場合は無視。空でない場合のみ設定
            currencyOptions.set(currency, unitAmount);
        }
    }
    return currencyOptions;
}

/**
  * 商品オブジェクトを作成する
  * @param {String} oauth 認証設定
  * @param {String} name 商品名
  * @param {String} description 商品説明
  * @param {String} currency 通貨
  * @param {String} unitAmount 単価
  * @param {Map<String, String>} currencyOptions サブ通貨
  * @return {Object} returnObj
  * @return {String} returnObj.productId 商品オブジェクトの ID
  * @return {String} returnObj.priceId 価格オブジェクトの ID
  */
function createProduct(auth, name, description, currency, unitAmount, currencyOptions) {
    const apiUri = 'https://api.stripe.com/v1/products';
    let request = httpClient.begin()
        .authSetting(auth) // with "Authorization: Bearer XX"
        .header('Stripe-Version', STRIPE_API_VERSION)
        .formParam('name', name)
        .formParam('default_price_data[currency]', currency)
        .formParam('default_price_data[unit_amount]', unitAmount);
    if (description !== '') {
        request = request.formParam('description', description);
    }
    currencyOptions.forEach((subUnitAmount, subCurrency) => {
        request = request.formParam(`default_price_data[currency_options][${subCurrency}][unit_amount]`, subUnitAmount);
    });
    const response = request.post(apiUri);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        engine.log(responseStr);
        throw `Failed to create product. status: ${status}`;
    }
    const productObj = JSON.parse(responseStr);
    const productId = productObj.id;
    const priceId = productObj.default_price;
    return {productId, priceId};
}

/**
  * データ項目にデータを保存する
  * @param {DataDefinitionView} dataDef データ項目の DataDefinitionView
  * @param {Object} value 保存する値
  */
function setData(dataDef, value) {
    if (dataDef !== null) {
        engine.setData(dataDef, value);
    }
}

    
%d人のブロガーが「いいね」をつけました。