2022-08-03 (C) Questetra, Inc. (MIT License) 2 https://support.questetra.com/bpmn-icons/service-task-stripe-invoice-charge/ https://support.questetra.com/ja/bpmn-icons/service-task-stripe-invoice-charge/ This item charges the customer based on a finalized invoice on Stripe. If the default payment method fails, this item tries to charge other payment methods (card) attached to the customer. An error occurs if no charge succeeded. この工程は、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= { configs.put('conf_Auth', 'Stripe'); // 請求書 ID が保存されている文字型データ項目(単一行)を準備 const invoiceIdDef = engine.createDataDefinition('確定済み請求書の ID', 1, 'q_invoiceId', 'STRING_TEXTFIELD'); engine.setData(invoiceIdDef, invoiceId); configs.putObject('conf_InvoiceId', invoiceIdDef); configs.putObject('conf_SendReceipt', sendReceipt); }; /** * 請求書 ID が空 */ test('Invoice ID is blank', () => { prepareConfigs(null, true); expect(execute).toThrow('Invoice ID is blank.'); }); /** * 請求書を取得する API リクエストのテスト * @param {Object} request * @param request.url * @param request.method * @param invoiceId */ const assertGetInvoiceRequest = ({url, method}, invoiceId) => { expect(url).toEqual(`https://api.stripe.com/v1/invoices/${encodeURIComponent(invoiceId)}`); expect(method).toEqual('GET'); }; /** * 請求書を取得する HTTP リクエストで失敗 */ test('Fail to retrieve invoice', () => { prepareConfigs('in_00001', true); httpClient.setRequestHandler((request) => { assertGetInvoiceRequest(request, 'in_00001'); return httpClient.createHttpResponse(400, 'application/json', '{}'); }); expect(execute).toThrow('Failed to retrieve invoice. status: 400'); }); /** * 請求書のステータスが不正 - ドラフト状態 */ test('Invalid status - draft', () => { prepareConfigs('in_00002', true); httpClient.setRequestHandler((request) => { assertGetInvoiceRequest(request, 'in_00002'); return httpClient.createHttpResponse(200, 'application/json', '{"status": "draft"}'); }); expect(execute).toThrow('The invoice is still draft. It needs to be finalized first.'); }); /** * 請求書のステータスが不正 - 支払い済み */ test('Invalid status - paid', () => { prepareConfigs('in_00003', true); httpClient.setRequestHandler((request) => { assertGetInvoiceRequest(request, 'in_00003'); return httpClient.createHttpResponse(200, 'application/json', '{"status": "paid"}'); }); expect(execute).toThrow('The invoice is already paid.'); }); /** * 請求書のステータスが不正 - 無効 */ test('Invalid status - void', () => { prepareConfigs('in_00004', true); httpClient.setRequestHandler((request) => { assertGetInvoiceRequest(request, 'in_00004'); return httpClient.createHttpResponse(200, 'application/json', '{"status": "void"}'); }); expect(execute).toThrow('The invoice is void.'); }); /** * 請求書を取得する API リクエストのレスポンスボディを作成する * @param status * @param customerId * @param paymentIntentId * @return invoiceRes */ const invoiceRes = (status, customerId, paymentIntentId) => { const invoiceObj = { 'status': status, 'customer': customerId, 'payment_intent': paymentIntentId }; return JSON.stringify(invoiceObj); }; /** * 顧客を取得する API リクエストのテスト * @param {Object} request * @param request.url * @param request.method * @param customerId */ const assertGetCustomerRequest = ({url, method}, customerId) => { expect(url).toEqual(`https://api.stripe.com/v1/customers/${customerId}`); expect(method).toEqual('GET'); }; /** * 顧客を取得する HTTP リクエストで失敗 */ test('Fail to retrieve customer', () => { prepareConfigs('in_00021', true); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00021'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00001', 'pi_00001')); } assertGetCustomerRequest(request, 'cus_00001'); return httpClient.createHttpResponse(400, 'application/json', '{}'); }); expect(execute).toThrow('Failed to retrieve customer. status: 400'); }); /** * 顧客が削除済み */ test('Customer is deleted', () => { prepareConfigs('in_00022', true); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00022'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00002', 'pi_00002')); } assertGetCustomerRequest(request, 'cus_00002'); return httpClient.createHttpResponse(200, 'application/json', '{"deleted": true}'); }); expect(execute).toThrow('The customer is deleted.'); }); /** * 顧客を取得する API リクエストのレスポンスボディを作成する * @param email * @param defaultPaymentMethodId * @param defaultSourceId * @return customerRes */ const customerRes = (email, defaultPaymentMethodId, defaultSourceId) => { const customerObj = { 'email': email, 'invoice_settings': { 'default_payment_method': defaultPaymentMethodId }, 'default_source': defaultSourceId }; return JSON.stringify(customerObj); }; /** * 「顧客に領収書をメール送付する」が true なのに顧客のメールアドレスが未設定 */ test('Customer email is null while sendReceipt is true', () => { prepareConfigs('in_00023', true); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00023'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00003', 'pi_00003')); } assertGetCustomerRequest(request, 'cus_00003'); return httpClient.createHttpResponse(200, 'application/json', customerRes(null, 'pm_00001', null)); }); expect(execute).toThrow("The customer's email is not set. Unable to send the receipt."); }); /** * 支払オブジェクトを更新する API リクエストのテスト * @param {Object} request * @param request.url * @param request.method * @param request.contentType * @param request.body * @param paymentIntentId * @param receiptEmail */ const assertUpdatePaymentIntentRequest = ({url, method, contentType, body}, paymentIntentId, receiptEmail) => { expect(url).toEqual(`https://api.stripe.com/v1/payment_intents/${paymentIntentId}`); expect(method).toEqual('POST'); expect(contentType).startsWith('application/x-www-form-urlencoded'); expect(body).toEqual(`receipt_email=${encodeURIComponent(receiptEmail)}`); }; /** * 支払オブジェクトを更新する HTTP リクエストで失敗 */ test('Fail to update payment intent', () => { prepareConfigs('in_00031', true); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00031'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00001', 'pi_00001')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00001'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus1@example.com', 'pm_00001', null)); } assertUpdatePaymentIntentRequest(request, 'pi_00001', 'cus1@example.com'); return httpClient.createHttpResponse(400, 'application/json', '{}'); }); expect(execute).toThrow('Failed to update payment intent. status: 400'); }); /** * 請求書で課金する API リクエストのテスト * @param {Object} request * @param request.url * @param request.method * @param request.contentType * @param request.body * @param invoiceId * @param paymentMethodId */ const assertChargeByInvoiceRequest = ({url, method, contentType, body}, invoiceId, paymentMethodId) => { expect(url).toEqual(`https://api.stripe.com/v1/invoices/${encodeURIComponent(invoiceId)}/pay`); expect(method).toEqual('POST'); expect(contentType).startsWith('application/x-www-form-urlencoded'); expect(body).toEqual(`payment_method=${paymentMethodId}`); }; /** * デフォルトの支払方法への課金に成功 */ test('Success - default payment method', () => { prepareConfigs('in_00041', true); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00041'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00001', 'pi_00001')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00001'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus1@example.com', 'pm_00001', null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00001', 'cus1@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } assertChargeByInvoiceRequest(request, 'in_00041', 'pm_00001'); return httpClient.createHttpResponse(200, 'application/json', '{}'); }); execute(); }); /** * デフォルトの支払方法への課金に成功 * 領収書をメール送付しない場合 */ test('Success - default payment method, sendReceipt is false', () => { prepareConfigs('in_00042', false); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00042'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00002', 'pi_00002')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00002'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus2@example.com', 'pm_00002', null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00002', ''); // 領収書送付先メールアドレスが空に設定される reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } assertChargeByInvoiceRequest(request, 'in_00042', 'pm_00002'); return httpClient.createHttpResponse(200, 'application/json', '{}'); }); execute(); }); /** * デフォルトの支払方法への課金に成功 * 領収書をメール送付しない場合は、メールアドレスが未設定でもエラーにならない */ test('Success - default payment method, sendReceipt is false, customerEmail is null', () => { prepareConfigs('in_00042', false); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00042'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00002', 'pi_00002')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00002'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes(null, 'pm_00002', null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00002', ''); // 領収書送付先メールアドレスが空に設定される reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } assertChargeByInvoiceRequest(request, 'in_00042', 'pm_00002'); return httpClient.createHttpResponse(200, 'application/json', '{}'); }); execute(); }); /** * デフォルトの支払方法への課金に成功 * uncollectible な請求書の場合 */ test('Success - default payment method, uncollectible invoice', () => { prepareConfigs('in_00043', true); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00043'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('uncollectible', 'cus_00003', 'pi_00003')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00003'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus3@example.com', 'pm_00003', null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00003', 'cus3@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } assertChargeByInvoiceRequest(request, 'in_00043', 'pm_00003'); return httpClient.createHttpResponse(200, 'application/json', '{}'); }); execute(); }); /** * default_source として登録されているデフォルトの支払方法への課金に成功 */ test('Success - default payment method (default_source)', () => { prepareConfigs('in_00044', true); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00044'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00004', 'pi_00004')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00004'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus4@example.com', null, 'source_00004')); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00004', 'cus4@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } assertChargeByInvoiceRequest(request, 'in_00044', 'source_00004'); return httpClient.createHttpResponse(200, 'application/json', '{}'); }); execute(); }); /** * 顧客の支払方法 (カード) の一覧を取得する API リクエストのテスト * @param {Object} request * @param request.url * @param request.method * @param customerId */ const assertGetCustomerPaymentMethodsRequest = ({url, method}, customerId) => { expect(url).toEqual(`https://api.stripe.com/v1/customers/${customerId}/payment_methods?type=card&limit=100`); expect(method).toEqual('GET'); }; /** * デフォルトの支払方法が未設定で、顧客の支払方法 (カード) の一覧を取得する HTTP リクエストで失敗 */ test('Fail to retrieve payment methods', () => { prepareConfigs('in_00051', true); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00051'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00001', 'pi_00001')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00001'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus1@example.com', null, null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00001', 'cus1@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } assertGetCustomerPaymentMethodsRequest(request, 'cus_00001'); return httpClient.createHttpResponse(400, 'application/json', '{}'); }); expect(execute).toThrow("Failed to get the customer's payment methods. status: 400"); }); /** * 顧客の支払方法 (カード) の一覧を取得する API リクエストのレスポンスボディを作成する * @param paymentMethodNum * @return paymentMethodsRes */ const paymentMethodsRes = (paymentMethodNum) => { const paymentMethodObjects = []; for (let i = 0; i < paymentMethodNum; i++) { const paymentMethodObj = { 'id': `pm_${i+1}` }; paymentMethodObjects.push(paymentMethodObj); } return JSON.stringify({'data': paymentMethodObjects}); }; /** * デフォルトの支払方法が未設定で、顧客の支払方法 (カード) の一覧が空 */ test('No card-type payment methods', () => { prepareConfigs('in_00052', true); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00052'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00002', 'pi_00002')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00002'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus2@example.com', null, null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00002', 'cus2@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } assertGetCustomerPaymentMethodsRequest(request, 'cus_00002'); return httpClient.createHttpResponse(200, 'application/json', paymentMethodsRes(0)); }); expect(execute).toThrow('The customer has no card-type payment methods.'); }); const HTTP_LIMIT = httpClient.getRequestingLimit(); /** * デフォルトの支払方法が未設定で、顧客の支払方法 (カード) のすべてで課金に失敗 */ test('No payment method succeeded - without default payment method', () => { prepareConfigs('in_00061', true); let reqCount = 0; let pmCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00061'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00001', 'pi_00001')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00001'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus1@example.com', null, null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00001', 'cus1@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } if (reqCount === 3) { assertGetCustomerPaymentMethodsRequest(request, 'cus_00001'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', paymentMethodsRes(HTTP_LIMIT - reqCount)); } // 各 Payment Method に課金を試み、すべて失敗 const paymentMethodId = `pm_${pmCount+1}`; assertChargeByInvoiceRequest(request, 'in_00061', paymentMethodId); pmCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); }); expect(execute).toThrow('No payment method succeeded.'); }); /** * デフォルトの支払方法が未設定で、顧客の支払方法 (カード) のうち一つで課金に成功 */ test('Success - without default payment method, one of the cards succeeds', () => { prepareConfigs('in_00062', true); let reqCount = 0; let pmCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00062'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00002', 'pi_00002')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00002'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus2@example.com', null, null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00002', 'cus2@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } if (reqCount === 3) { assertGetCustomerPaymentMethodsRequest(request, 'cus_00002'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', paymentMethodsRes(HTTP_LIMIT - reqCount)); } // 各 Payment Method に課金を試みる const paymentMethodId = `pm_${pmCount + 1}`; assertChargeByInvoiceRequest(request, 'in_00062', paymentMethodId); if (reqCount < HTTP_LIMIT - 1) { // 最後から 1 つ前までは失敗 reqCount++; pmCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); } // 最後の 1 つは成功 return httpClient.createHttpResponse(200, 'application/json', '{}'); }); execute(); }); // スクリプトエンジンの HTTP リクエスト数の上限 const REQ_LIMIT = httpClient.getRequestingLimit(); /** * デフォルトの支払方法が未設定で、顧客の支払方法 (カード) への課金を試みているあいだに HTTP リクエスト数上限を超える */ test('Number of HTTP requests exceeds the limit - without default payment method', () => { prepareConfigs('in_00063', true); let reqCount = 0; let pmCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00063'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00003', 'pi_00003')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00003'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus3@example.com', null, null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00003', 'cus3@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } if (reqCount === 3) { assertGetCustomerPaymentMethodsRequest(request, 'cus_00003'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', paymentMethodsRes(HTTP_LIMIT - reqCount + 1)); } // 各 Payment Method に課金を試み、すべて失敗 const paymentMethodId = `pm_${pmCount + 1}`; assertChargeByInvoiceRequest(request, 'in_00063', paymentMethodId); pmCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); }); expect(execute).toThrow(`HTTP requests must be up to ${REQ_LIMIT}.`); // スクリプトエンジンのエラー }); /** * デフォルトの支払方法への課金に失敗し、顧客の支払方法 (カード) のすべてで課金に失敗 */ test('No payment method succeeded - default payment method fails', () => { prepareConfigs('in_00071', true); let reqCount = 0; let pmCount = 0; const defaultPmIndex = 1; const defaultPmId = `pm_${defaultPmIndex}`; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00071'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00001', 'pi_00001')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00001'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus1@example.com', defaultPmId, null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00001', 'cus1@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } if (reqCount === 3) { // デフォルトの支払方法への課金に失敗 assertChargeByInvoiceRequest(request, 'in_00071', defaultPmId); reqCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); } if (reqCount === 4) { assertGetCustomerPaymentMethodsRequest(request, 'cus_00001'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', paymentMethodsRes(HTTP_LIMIT - reqCount + 1)); } // デフォルトの支払方法以外の各 Payment Method に課金を試み、すべて失敗 if (pmCount + 1 === defaultPmIndex) { // デフォルトの支払方法と一致するものは飛ばす pmCount++; } const paymentMethodId = `pm_${pmCount + 1}`; assertChargeByInvoiceRequest(request, 'in_00071', paymentMethodId); pmCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); }); expect(execute).toThrow('No payment method succeeded.'); }); /** * デフォルトの支払方法への課金に失敗し、顧客の支払方法 (カード) のうち一つで課金に成功 */ test('Success - default payment method fails, one of the cards succeeds', () => { prepareConfigs('in_00072', true); let reqCount = 0; let pmCount = 0; const defaultPmIndex = 2; const defaultPmId = `pm_${defaultPmIndex}`; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00072'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00002', 'pi_00002')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00002'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus2@example.com', defaultPmId, null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00002', 'cus2@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } if (reqCount === 3) { // デフォルトの支払方法への課金に失敗 assertChargeByInvoiceRequest(request, 'in_00072', defaultPmId); reqCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); } if (reqCount === 4) { assertGetCustomerPaymentMethodsRequest(request, 'cus_00002'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', paymentMethodsRes(HTTP_LIMIT - reqCount + 1)); } // 各 Payment Method に課金を試みる if (pmCount + 1 === defaultPmIndex) { // デフォルトの支払方法と一致するものは飛ばす pmCount++; } const paymentMethodId = `pm_${pmCount + 1}`; assertChargeByInvoiceRequest(request, 'in_00072', paymentMethodId); if (reqCount < HTTP_LIMIT - 1) { // 最後から 1 つ前までは失敗 reqCount++; pmCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); } // 最後の 1 つは成功 return httpClient.createHttpResponse(200, 'application/json', '{}'); }); execute(); }); /** * デフォルトの支払方法への課金に失敗し、顧客の支払方法 (カード) への課金を試みているあいだに HTTP リクエスト数上限を超える */ test('Number of HTTP requests exceeds the limit - default payment method fails', () => { prepareConfigs('in_00073', true); let reqCount = 0; let pmCount = 0; const defaultPmIndex = 3; const defaultPmId = `pm_${defaultPmIndex}`; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00073'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00003', 'pi_00003')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00003'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus3@example.com', defaultPmId, null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00003', 'cus3@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } if (reqCount === 3) { // デフォルトの支払方法への課金に失敗 assertChargeByInvoiceRequest(request, 'in_00073', defaultPmId); reqCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); } if (reqCount === 4) { assertGetCustomerPaymentMethodsRequest(request, 'cus_00003'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', paymentMethodsRes(HTTP_LIMIT - reqCount + 2)); } // デフォルトの支払方法以外の各 Payment Method に課金を試み、すべて失敗 if (pmCount + 1 === defaultPmIndex) { // デフォルトの支払方法と一致するものは飛ばす pmCount++; } const paymentMethodId = `pm_${pmCount + 1}`; assertChargeByInvoiceRequest(request, 'in_00073', paymentMethodId); pmCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); }); expect(execute).toThrow(`HTTP requests must be up to ${REQ_LIMIT}.`); // スクリプトエンジンのエラー }); /** * default_source として登録されているデフォルトの支払方法への課金に失敗し、顧客の支払方法 (カード) のうち一つで課金に成功 */ test('Success - default source fails, one of the cards succeeds', () => { prepareConfigs('in_00074', true); let reqCount = 0; let pmCount = 0; const defaultPmIndex = 2; const defaultPmId = `pm_${defaultPmIndex}`; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00074'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00004', 'pi_00004')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00004'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus4@example.com', null, defaultPmId)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00004', 'cus4@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } if (reqCount === 3) { // デフォルトの支払方法への課金に失敗 assertChargeByInvoiceRequest(request, 'in_00074', defaultPmId); reqCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); } if (reqCount === 4) { assertGetCustomerPaymentMethodsRequest(request, 'cus_00004'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', paymentMethodsRes(10)); } // 各 Payment Method に課金を試みる if (pmCount + 1 === defaultPmIndex) { // デフォルトの支払方法と一致するものは飛ばす pmCount++; } const paymentMethodId = `pm_${pmCount + 1}`; assertChargeByInvoiceRequest(request, 'in_00074', paymentMethodId); if (pmCount < 5) { // 途中までは失敗 pmCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); } // 途中で成功 return httpClient.createHttpResponse(200, 'application/json', '{}'); }); execute(); }); /** * デフォルトの支払方法への課金に失敗し、他の支払方法 (カード) が登録されていない */ test('No payment method succeeded - only default payment method', () => { prepareConfigs('in_00075', true); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertGetInvoiceRequest(request, 'in_00075'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', invoiceRes('open', 'cus_00005', 'pi_00005')); } if (reqCount === 1) { assertGetCustomerRequest(request, 'cus_00005'); reqCount++; return httpClient .createHttpResponse(200, 'application/json', customerRes('cus5@example.com', 'pm_1', null)); } if (reqCount === 2) { assertUpdatePaymentIntentRequest(request, 'pi_00005', 'cus5@example.com'); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } if (reqCount === 3) { // デフォルトの支払方法への課金に失敗 assertChargeByInvoiceRequest(request, 'in_00075', 'pm_1'); reqCount++; return httpClient.createHttpResponse(401, 'application/json', '{}'); } assertGetCustomerPaymentMethodsRequest(request, 'cus_00005') return httpClient .createHttpResponse(200, 'application/json', paymentMethodsRes(1)); // デフォルトの支払方法のみ }); expect(execute).toThrow('No payment method succeeded.'); }); ]]>