Stripe: Send Invoice

Stripe: Send Invoice

Stripe: 請求書をメール送付

This item sends a finalized invoice on Stripe to the customer by email. The customer can pay the invoice via the payment link included in the email.

Auto Step icon
Basic Configs
Step Name
Note
Configs for this Auto Step
conf_Auth
C1: Authorization Setting in which API Secret Key is set *
conf_InvoiceId
C2: Finalized Invoice ID *
conf_NotSetupFutureUsage
C3: Not reuse the customer’s card details for future invoices
conf_SendReceipt
C4: Email the receipt to the customer when the payment completed

Notes

  • To get Stripe’s API Secret Key, visit https://dashboard.stripe.com/apikeys (Stripe login required)
  • When C3 is off, invoices sent by this item can only be paid by credit or debit cards

Capture

See also

Script (click to open)
  • An XML file that contains the code below is available to download
    • stripe-invoice-send.xml (C) Questetra, Inc. (MIT License)
    • If you are using Professional, you can modify the contents of this file and use it as your own add-on auto step


const STRIPE_API_VERSION = '2022-08-01';

function main(){
    //// == Config Retrieving / 工程コンフィグの参照 ==
    const auth = configs.getObject('conf_Auth');
    const invoiceId = retrieveInvoiceId();
    const notSetupFutureUsage = configs.getObject('conf_NotSetupFutureUsage');
    const sendReceipt = configs.getObject('conf_SendReceipt');

    //// == Calculating / 演算 ==
    const {customerId, paymentIntentId} = checkInvoice(auth, invoiceId);
    const customerEmail = checkCustomer(auth, customerId);
    if (!notSetupFutureUsage) { // カード情報を再利用するための設定を行う場合、支払方法をカードのみに設定する
        updatePaymentMethodTypes(auth, invoiceId);
    }
    updatePaymentIntent(auth, paymentIntentId, notSetupFutureUsage, sendReceipt, customerEmail);
    sendInvoice(auth, invoiceId);
}

/**
  * config から請求書の ID を読み出す。空文字列の場合はエラー
  * @return {String} invoiceId 請求書の ID
  */
function retrieveInvoiceId() {
    const invoiceId = engine.findData(configs.getObject('conf_InvoiceId'));
    if (invoiceId === null) {
        throw new Error('Invoice ID is blank.');
    }
    return invoiceId;
}

/**
  * 請求書のステータスをチェックし、顧客 ID と支払オブジェクトの ID を返す
  * - ステータスが open, uncollectible 以外の場合はエラー
  * - collection_method が send_invoice でない場合はエラー
  * @param {AuthSettingWrapper} auth  HTTP 認証設定 トークン直接指定
  * @param {String} invoiceId 請求書の ID
  * @return {Object} returnObj
  * @return {String} returnObj.customerId 顧客 ID
  * @return {String} returnObj.paymentIntentId 支払オブジェクトの ID
  */
function checkInvoice(auth, invoiceId) {
    const apiUri = `https://api.stripe.com/v1/invoices/${encodeURIComponent(invoiceId)}`;
    const response = httpClient.begin()
        .authSetting(auth) // with "Authorization: Bearer XX"
        .header('Stripe-Version', STRIPE_API_VERSION)
        .get(apiUri);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) { // 削除済みの場合もエラーレスポンス
        engine.log(responseStr);
        throw new Error(`Failed to retrieve invoice. status: ${status}`);
    }
    const invoiceObj = JSON.parse(responseStr);
    switch (invoiceObj.status) {
        case 'draft':
            throw new Error('The invoice is still draft. It needs to be finalized first.');
        case 'paid':
            throw new Error('The invoice is already paid.');
        case 'void':
            throw new Error('The invoice is void.');
        default: // open or uncollectible
            // do nothing
    }
    if (invoiceObj.collection_method !== 'send_invoice') {
        // collection_method が send_invoice でない場合は、Stripe の仕様で請求書をメール送付できない
        throw new Error('The collection method of the invoice is not send_invoice.');
    }
    const customerId = invoiceObj.customer;
    const paymentIntentId = invoiceObj.payment_intent;
    return {customerId, paymentIntentId};
}

/**
  * 顧客をチェックし、顧客のメールアドレスを返す
  * - 顧客が削除済みの場合、エラー
  * - 顧客のメールアドレスが設定されていない場合、エラー
  * @param {AuthSettingWrapper} auth  HTTP 認証設定 トークン直接指定
  * @param {String} customerId 顧客 ID
  * @return {String} customerEmail 顧客のメールアドレス
  */
function checkCustomer(auth, customerId) {
    const apiUri = `https://api.stripe.com/v1/customers/${customerId}`;
    const response = httpClient.begin()
        .authSetting(auth) // with "Authorization: Bearer XX"
        .header('Stripe-Version', STRIPE_API_VERSION)
        .get(apiUri);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        engine.log(responseStr);
        throw new Error(`Failed to retrieve customer. status: ${status}`);
    }
    const customerObj = JSON.parse(responseStr);
    if (customerObj.deleted) {
        throw new Error('The customer is deleted.');
    }
    const customerEmail = customerObj.email;
    if (customerEmail === null) {
        // 顧客のメールアドレス以外に「請求先メールアドレス」もダッシュボードからは設定できるが、API では取得不可
        // 「請求先メールアドレス」の設定有無によらず、顧客のメールアドレスが設定されていない場合はエラーにする
        throw new Error("The customer's email is not set. Update the customer or send the invoice from Stripe dashboard.");
    }
    return customerEmail;
}

/**
  * 請求書を更新し、支払方法をカードのみにする
  * @param {AuthSettingWrapper} auth  HTTP 認証設定 トークン直接指定
  * @param {String} invoiceId 請求書の ID
  */
function updatePaymentMethodTypes(auth, invoiceId) {
    const apiUri = `https://api.stripe.com/v1/invoices/${encodeURIComponent(invoiceId)}`;
    const response = httpClient.begin()
        .authSetting(auth) // with "Authorization: Bearer XX"
        .header('Stripe-Version', STRIPE_API_VERSION)
        .formParam('payment_settings[payment_method_types][0]', 'card')
        .post(apiUri);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) { // 請求書のステータスが uncollectible の場合、更新に失敗
        engine.log(responseStr);
        throw new Error(`Failed to update invoice. status: ${status}`);
    }
}

/**
  * 支払オブジェクトを更新し、
  * - カード情報を再利用するための設定を行うかどうかを設定する
  * - 領収書送付先メールアドレスを設定する
  * @param {AuthSettingWrapper} auth  HTTP 認証設定 トークン直接指定
  * @param {String} paymentIntentId 支払オブジェクトの ID
  * @param {boolean} notSetupFutureUsage カード情報を再利用するための設定を行わないかどうか
  * @param {boolean} sendReceipt 領収書をメール送付するかどうか
  * @param {String} customerEmail 顧客のメールアドレス
  */
function updatePaymentIntent(auth, paymentIntentId, notSetupFutureUsage, sendReceipt, customerEmail) {
    let setupFutureUsage = '';
    if (!notSetupFutureUsage) {
        setupFutureUsage = 'off_session';
    }
    let receiptEmail = '';
    if (sendReceipt) {
        receiptEmail = customerEmail;
    }
    const apiUri = `https://api.stripe.com/v1/payment_intents/${paymentIntentId}`;
    const response = httpClient.begin()
        .authSetting(auth) // with "Authorization: Bearer XX"
        .header('Stripe-Version', STRIPE_API_VERSION)
        .formParam('setup_future_usage', setupFutureUsage)
        .formParam('payment_method_options[card][setup_future_usage]', 'none') // カード固有の設定を解除
        .formParam('receipt_email', receiptEmail)
        .post(apiUri);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        engine.log(responseStr);
        throw new Error(`Failed to update payment intent. status: ${status}`);
    }
}

/**
  * 請求書をメール送付する
  * @param {AuthSettingWrapper} auth  HTTP 認証設定 トークン直接指定
  * @param {String} invoiceId 請求書の ID
  */
function sendInvoice(auth, invoiceId) {
    const apiUri = `https://api.stripe.com/v1/invoices/${encodeURIComponent(invoiceId)}/send`;
    const response = httpClient.begin()
        .authSetting(auth) // with "Authorization: Bearer XX"
        .header('Stripe-Version', STRIPE_API_VERSION)
        .post(apiUri);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        // 顧客のメールアドレスが未設定の場合でもここではエラーにならず、レスポンスからも送信先はわからない
        engine.log(responseStr);
        throw new Error(`Failed to send invoice. status: ${status}`);
    }
}

    

Discover more from Questetra Support

Subscribe now to keep reading and get access to the full archive.

Continue reading