2022-09-12 (C) Questetra, Inc. (MIT License) 2 https://support.questetra.com/bpmn-icons/service-task-stripe-invoice-finalize/ https://support.questetra.com/ja/bpmn-icons/service-task-stripe-invoice-finalize/ This item finalizes a draft invoice on Stripe, which allows you to send the invoice or charge the customer. この工程は、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); // 支払い期日が保存されている日時型データ項目を準備 const dueDateDef = engine.createDataDefinition('支払い期日', 2, 'q_dueDatetime', 'DATETIME'); const dueDatetime = new com.questetra.bpms.util.AddableTimestamp().addMinutes(minutesUntilDueDate); engine.setData(dueDateDef, dueDatetime); configs.putObject('conf_DueDate', dueDateDef); return Math.floor(dueDatetime.getTime() / 1000).toString(); }; const ONE_DAY = 60 * 24; // minutes /** * 請求書 ID が空 */ test('Invoice ID is blank', () => { prepareConfigs(null, ONE_DAY); expect(execute).toThrow('Invoice ID is blank.'); }); /** * 支払い期日が空 */ test('Due date is not set', () => { prepareConfigs('in_00001', ONE_DAY); const dueDateDef = engine.createDataDefinition('新しい支払い期日', 3, 'q_newDueDatetime', 'DATETIME'); configs.putObject('conf_DueDate', dueDateDef); expect(execute).toThrow('Due date is not set.'); }); /** * 支払い期日が過去 */ test('Due date is not in the future', () => { prepareConfigs('in_00001', -1); expect(execute).toThrow('Due date must be future.'); }); const MAX_DAYS = 1800; /** * 支払い期日が遠すぎる */ test('Due date is too far in the future', () => { const maxDays = 1800; prepareConfigs('in_00001', ONE_DAY * MAX_DAYS + 1); expect(execute).toThrow('Number of days until due date must be less than or equal to 1800.'); }); /** * 請求書ドラフトを更新する API リクエストのテスト * @param {Object} request * @param request.url * @param request.method * @param request.headers * @param request.contentType * @param request.body * @param invoiceId * @param dueDateTimestamp */ const assertUpdateInvoiceRequest = ({url, method, headers, contentType, body}, invoiceId, dueDateTimestamp) => { expect(url).toEqual(`https://api.stripe.com/v1/invoices/${encodeURIComponent(invoiceId)}`); expect(method).toEqual('POST'); expect(headers.get('Stripe-Version')).toEqual(STRIPE_VERSION); expect(contentType).startsWith('application/x-www-form-urlencoded'); expect(body).toEqual(`collection_method=send_invoice&due_date=${dueDateTimestamp}`); }; /** * 請求書ドラフトを更新する HTTP リクエストで失敗 */ test('Fail to update invoice', () => { const dueDateTimestamp = prepareConfigs('in_00021', ONE_DAY); httpClient.setRequestHandler((request) => { assertUpdateInvoiceRequest(request, 'in_00021', dueDateTimestamp); return httpClient.createHttpResponse(400, 'application/json', '{}'); }); expect(execute).toThrow('Failed to update invoice. status: 400'); }); /** * 請求書ドラフトを確定する API リクエストのテスト * @param {Object} request * @param request.url * @param request.method * @param request.headers * @param request.contentType * @param request.body * @param invoiceId */ const assertFinalizeInvoiceRequest = ({url, method, headers, contentType, body}, invoiceId) => { expect(url).toEqual(`https://api.stripe.com/v1/invoices/${encodeURIComponent(invoiceId)}/finalize`); expect(method).toEqual('POST'); expect(headers.get('Stripe-Version')).toEqual(STRIPE_VERSION); expect(contentType).startsWith('application/x-www-form-urlencoded'); expect(body).toEqual('auto_advance=false'); }; /** * 請求書ドラフトを確定する HTTP リクエストで失敗 */ test('Fail to finalize invoice', () => { const dueDateTimestamp = prepareConfigs('in_00031', ONE_DAY); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertUpdateInvoiceRequest(request, 'in_00031', dueDateTimestamp); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } assertFinalizeInvoiceRequest(request, 'in_00031'); return httpClient.createHttpResponse(400, 'application/json', '{}'); }); expect(execute).toThrow('Failed to finalize invoice. status: 400'); }); /** * 成功 - 支払い期日まで 1 日 */ test('Success - 1 day until due date', () => { const dueDateTimestamp = prepareConfigs('in_00032', ONE_DAY); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertUpdateInvoiceRequest(request, 'in_00032', dueDateTimestamp); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } assertFinalizeInvoiceRequest(request, 'in_00032'); return httpClient.createHttpResponse(200, 'application/json', '{}'); }); execute(); }); /** * 成功 - 支払い期日まで最大日数 */ test('Success - maximum days until due date', () => { const dueDateTimestamp = prepareConfigs('in_00033', ONE_DAY * MAX_DAYS); let reqCount = 0; httpClient.setRequestHandler((request) => { if (reqCount === 0) { assertUpdateInvoiceRequest(request, 'in_00033', dueDateTimestamp); reqCount++; return httpClient.createHttpResponse(200, 'application/json', '{}'); } assertFinalizeInvoiceRequest(request, 'in_00033'); return httpClient.createHttpResponse(200, 'application/json', '{}'); }); execute(); }); ]]>