2024-04-30
(C) Questetra, Inc. (MIT License)
3
2
https://support.questetra.com/bpmn-icons/service-task-stripe-metadata-update/
https://support.questetra.com/ja/bpmn-icons/service-task-stripe-metadata-update/
This item updates metadata of a customer, product or invoice on Stripe. Metadata Fields whose keys are not
specified remain unchanged.
この工程は、Stripe 上の顧客、商品または請求書のメタデータを更新します。キーを指定していないメタデータフィールドは変更されません。
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAvJJREFUWEfF
l19I01EUxz/XKZqWNbVS6cH+UfSUGQlCD0EQRCkoFDkDUzENi6IgkB4sKEgjDStFnVlzalC9+BBR
IEFBEeVbFP3R/lhRpLRpKHO78dtv021u+pszfnv87Zzv+dxzzj33XoHOP6E1fvleGe9KJF/CDiSZ
CDIAo8d/BMkggn4BfVE27rX0ir9atOcEKC6WqdEOTkuoAOK0iALjAponY7jY0SF+zOYzK0CJSVYI
uAQkaAwcaDYm4VS7VTSH8g8JUFokryOpnGdgfzdBk7lTHAmmFRSgxCS7BBxYkOAeEQnd7VZRGKg5
A2BBVz4z2oxM+AF4at60kCsP1JJQ6dsTUwBKtxscvI+g4bRyjzljWOfdHVMAZSZZL+G4VpVI7AQ0
tFnFCUXDDaAMGWciv8PY55HEV3zHDTaSlWHlBigzySIJlvmoxsbBxHj4ngIOtllFpxug1CTNQMls
MjnbIS0d7t6etmpshe9DcKEmfACg3WwVpSpAoXyFIDNQZuMm2J2rfk1Ng6XL4NlTSE4Blwt6LOB0
QtEhkBKGvsCdHli9FnLzoe8h9L8MASfpN3eJLd4MDPscLFMeTTcgOhocDjXNi5fAr5+wYqUa+NOA
ClF9FiYnVdtHD2DnLpiYgNhYqKmGr5+DQoyYrSLJCyCDmdQ1gtEIdpv6r7LKbgscroKr9ZC/Dzpa
VIBr9VBeBYYoiDKotkLA/V7/svnGMVuFYuLugaAAx05C+ipIWa4KShe8eA7ZOdB4GQr2TwMMfoSM
NfDuLazfALY/YLdD9y148zp4GXwBgpag9goYk2BkGJ48hj15MDoK8QnQUAtZ26DrJrRaVMBRO9Sd
h7wC2JylAp87A9+G5ipBiCbU0ttbs6HiqFqCkA0XTCigCefchqFgFsWrO2TggxZcP5vpbRjJIAo7
rMfBbxDpPoo941i/w0gB0P04ViB0vZB4m0nXK5kXQtdL6X/JRLjXcp9M6Pcw8ULo+jTznXK6PU7n
O2q1+v0D2nRCMMki7aoAAAAASUVORK5CYII=
{
const sourceStr = 'あいうえおかきくけこ';
const string = sourceStr.repeat(Math.floor(length / sourceStr.length))
+ sourceStr.slice(0, length % sourceStr.length);
return string;
}
/**
* 設定の準備 - 顧客/商品/請求書 ID を文字型データ項目で指定
* @param id
* @param keys
* @param values
*/
const prepareConfigs = (id, keys, values) => {
const auth = httpClient.createAuthSettingToken('stripe API Key', 'stripe-secret-key-12345');
configs.putObject('conf_Auth', auth);
// 顧客/商品/請求書 ID が保存されている文字型データ項目(単一行)を準備し、設定
const idDef = engine.createDataDefinition('顧客/請求書 ID', 1, 'q_id', 'STRING_TEXTFIELD');
engine.setData(idDef, id);
configs.putObject('conf_Id', idDef);
for (let i = 0; i < FIELD_SIZE; i++) {
configs.put(`conf_Key${i+1}`, keys[i]);
configs.put(`conf_Value${i+1}`, values[i]);
}
}
const SAMPLE_KEYS = new Array(FIELD_SIZE).fill('').map((_, i) => `フィールド ${i+1}`);
const SAMPLE_VALUES = new Array(FIELD_SIZE).fill('').map((_, i) => `フィールド ${i+1} の値`);
/**
* 異常系のテスト
* @param errorMsg
*/
const assertError = (errorMsg) => {
let failed = false;
try {
main();
} catch (e) {
failed = true;
expect(e.message).toEqual(errorMsg);
}
if (!failed) {
fail('No error was thrown.');
}
};
/**
* ID が空
*/
test('ID is blank', () => {
prepareConfigs('', SAMPLE_KEYS, SAMPLE_VALUES);
assertError('Customer/Product/Invoice ID is blank.');
});
/**
* ID が不正な形式 - アンダーバーを含まない
*/
test('ID is invalid - no underscore', () => {
prepareConfigs('No-Underscore', SAMPLE_KEYS, SAMPLE_VALUES);
assertError('Customer/Product/Invoice ID must start with "cus_", "prod_" or "in_".');
});
/**
* ID が不正な形式 - アンダーバーより前の prefix が cus/prod/in でない
*/
test('ID is invalid - prefix not supported', () => {
prepareConfigs('pi_00001', SAMPLE_KEYS, SAMPLE_VALUES);
assertError('Customer/Product/Invoice ID must start with "cus_", "prod_" or "in_".');
});
/**
* 値が指定されているのにキーが空
*/
test('Key is blank while its value is set', () => {
prepareConfigs('cus_00001', SAMPLE_KEYS, SAMPLE_VALUES);
configs.put('conf_Key1', '');
assertError('C-V1 is set but C-K1 is blank.');
});
/**
* キーが重複
*/
test('Same key is set multiple times', () => {
prepareConfigs('cus_00001', SAMPLE_KEYS, SAMPLE_VALUES);
configs.put('conf_Key2', SAMPLE_KEYS[7]); // 2 番目と 8 番目が重複
assertError('Field Key "フィールド 8" is set multiple times.');
});
/**
* キーが長すぎる
*/
test('Key is too long', () => {
prepareConfigs('cus_00001', SAMPLE_KEYS, SAMPLE_VALUES);
configs.put('conf_Key3', createString(KEY_MAX_LENGTH + 1));
assertError(`C-K3 exceeds the limit of ${KEY_MAX_LENGTH} characters.`);
});
/**
* 値が長すぎる
*/
test('Value is too long', () => {
prepareConfigs('cus_00001', SAMPLE_KEYS, SAMPLE_VALUES);
configs.put('conf_Value4', createString(VALUE_MAX_LENGTH + 1));
assertError(`C-V4 exceeds the limit of ${VALUE_MAX_LENGTH} characters.`);
});
const ALL_BLANK = new Array(FIELD_SIZE).fill('');
/**
* メタデータの key, value がすべて空の場合、エラー
*/
test('No fields to update', () => {
prepareConfigs('cus_00001', ALL_BLANK, ALL_BLANK);
assertError('No metadata fields to update.');
});
/**
* メタデータを更新する API リクエストのテスト
* @param {Object} request
* @param request.url
* @param request.method
* @param request.headers
* @param request.contentType
* @param request.body
* @param expectedUrl
* @param keys
* @param values
*/
const assertUpdateMetadataRequest = ({url, method, headers, contentType, body}, expectedUrl, keys, values) => {
expect(url).toEqual(expectedUrl);
expect(method).toEqual('POST');
expect(headers.get('Stripe-Version')).toEqual(STRIPE_VERSION);
expect(contentType).startsWith('application/x-www-form-urlencoded');
const formParamList = [];
for (let i = 0; i < FIELD_SIZE; i++) {
pushToListIfNotBlank(formParamList, keys[i], values[i]);
}
const expectedBody = formParamList.join('&')
.replace(/%20/g, '+'); // HttpRequestWrapper#formParam() はスペースを + に置き換える
expect(body).toEqual(expectedBody);
};
/**
* key が空でない場合のみ、metadata[key]=value 形式の文字列を list に追加する
* @param list
* @param key
* @param value
*/
const pushToListIfNotBlank = (list, key, value) => {
if (key !== '') {
const encodedParamName = encodeURIComponent(`metadata[${key}]`);
list.push(`${encodedParamName}=${encodeURIComponent(value)}`);
}
};
/**
* 成功 - 顧客 ID を文字型データ項目で指定した場合
* キー、値は最大文字数でテスト
*/
test('Success - Customer ID set by string-type data item', () => {
const keys = JSON.parse(JSON.stringify(SAMPLE_KEYS)); // ディープコピー
keys[6] = createString(KEY_MAX_LENGTH);
const values = JSON.parse(JSON.stringify(SAMPLE_VALUES)); // ディープコピー
values[7] = createString(VALUE_MAX_LENGTH);
prepareConfigs('cus_00001', keys, values);
const expectedUrl = 'https://api.stripe.com/v1/customers/cus_00001';
httpClient.setRequestHandler((request) => {
assertUpdateMetadataRequest(request, expectedUrl, keys, values);
return httpClient.createHttpResponse(200, 'application/json', '{}');
});
main();
});
/**
* 成功 - 商品 ID を文字型データ項目で指定した場合
*/
test('Success - Product ID set by string-type data item', () => {
prepareConfigs('prod_00001', SAMPLE_KEYS, SAMPLE_VALUES);
const expectedUrl = 'https://api.stripe.com/v1/products/prod_00001';
httpClient.setRequestHandler((request) => {
assertUpdateMetadataRequest(request, expectedUrl, SAMPLE_KEYS, SAMPLE_VALUES);
return httpClient.createHttpResponse(200, 'application/json', '{}');
});
main();
});
/**
* 成功 - 請求書 ID を文字型データ項目で指定した場合
*/
test('Success - Invoice ID set by string-type data item', () => {
prepareConfigs('in_00001', SAMPLE_KEYS, SAMPLE_VALUES);
const expectedUrl = 'https://api.stripe.com/v1/invoices/in_00001';
httpClient.setRequestHandler((request) => {
assertUpdateMetadataRequest(request, expectedUrl, SAMPLE_KEYS, SAMPLE_VALUES);
return httpClient.createHttpResponse(200, 'application/json', '{}');
});
main();
});
/**
* メタデータを更新する HTTP リクエストで失敗
*/
test('Fail to update metadata', () => {
prepareConfigs('cus_00002', SAMPLE_KEYS, SAMPLE_VALUES);
const expectedUrl = 'https://api.stripe.com/v1/customers/cus_00002';
httpClient.setRequestHandler((request) => {
assertUpdateMetadataRequest(request, expectedUrl, SAMPLE_KEYS, SAMPLE_VALUES);
return httpClient.createHttpResponse(400, 'application/json', '{}');
});
assertError('Failed to update metadata. status: 400');
});
/**
* 成功 - key, value が空のものがある場合
*/
test('Success - Some keys and values are blank', () => {
const keys = JSON.parse(JSON.stringify(SAMPLE_KEYS)); // ディープコピー
keys[1] = '';
keys[3] = '';
const values = JSON.parse(JSON.stringify(SAMPLE_VALUES)); // ディープコピー
values[1] = ''; // key が空のものは値も空にする
values[3] = '';
values[5] = ''; // value だけ空のものがあってもよい
prepareConfigs('in_00002', keys, values);
const expectedUrl = 'https://api.stripe.com/v1/invoices/in_00002';
httpClient.setRequestHandler((request) => {
assertUpdateMetadataRequest(request, expectedUrl, keys, values);
return httpClient.createHttpResponse(200, 'application/json', '{}');
});
main();
});
/**
* 成功 - 顧客 ID を選択型データ項目で指定した場合
*/
test('Success - Customer ID set by select-type data item', () => {
prepareConfigs('', SAMPLE_KEYS, SAMPLE_VALUES);
// 選択型データ項目を準備し、設定
const customerId = 'cus_00010';
const idDef = engine.createDataDefinition('顧客 ID を選択', 2, 'q_customerIdSelect', 'SELECT_SINGLE');
const select = new java.util.ArrayList();
const item = engine.createItem(customerId, `${customerId} を選択`);
select.add(item);
engine.setData(idDef, select);
configs.putObject('conf_Id', idDef);
const expectedUrl = 'https://api.stripe.com/v1/customers/cus_00010';
httpClient.setRequestHandler((request) => {
assertUpdateMetadataRequest(request, expectedUrl, SAMPLE_KEYS, SAMPLE_VALUES);
return httpClient.createHttpResponse(200, 'application/json', '{}');
});
main();
});
/**
* ID を選択型データ項目で指定し、選択されていない場合
*/
test('Customer/Invoice ID set by select-type data item and not selected', () => {
prepareConfigs('cus_00011', SAMPLE_KEYS, SAMPLE_VALUES);
// 選択型データ項目を準備し、未選択のまま設定
const idDef = engine.createDataDefinition('ID を選択', 2, 'q_idSelect', 'SELECT_SINGLE');
configs.putObject('conf_Id', idDef);
assertError('Customer/Product/Invoice ID is not selected.');
});
/**
* 成功 - 請求書 ID を固定値で指定した場合
*/
test('Success - Invoice ID set as fixed value', () => {
prepareConfigs('', SAMPLE_KEYS, SAMPLE_VALUES);
configs.put('conf_Id', 'in_00011');
const expectedUrl = 'https://api.stripe.com/v1/invoices/in_00011';
httpClient.setRequestHandler((request) => {
assertUpdateMetadataRequest(request, expectedUrl, SAMPLE_KEYS, SAMPLE_VALUES);
return httpClient.createHttpResponse(200, 'application/json', '{}');
});
main();
});
]]>