Stripe: Send Invoice
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.
Configs: Common
  • Step Name
  • Note
Configs
  • C1: Authorization Setting in which API Secret Key is set *
  • C2: Finalized Invoice ID *
  • C3: Email the receipt to the customer when the payment completed

Notes

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


main();

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

    //// == Calculating / 演算 ==
    const {customerId, paymentIntentId} = checkInvoice(auth, invoiceId);
    const customerEmail = checkCustomer(auth, customerId);
    updatePaymentMethodTypes(auth, invoiceId);
    updatePaymentIntent(auth, paymentIntentId, 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 'Invoice ID is blank.';
    }
    return invoiceId;
}

/**
  * 請求書のステータスをチェックし、顧客 ID と支払オブジェクトの ID を返す
  * - ステータスが open, uncollectible 以外の場合はエラー
  * - collection_method が send_invoice でない場合はエラー
  * @param {String} oauth 認証設定
  * @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"
        .get(apiUri);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) { // 削除済みの場合もエラーレスポンス
        engine.log(responseStr);
        throw `Failed to retrieve invoice. status: ${status}`;
    }
    const invoiceObj = JSON.parse(responseStr);
    switch (invoiceObj.status) {
        case 'draft':
            throw 'The invoice is still draft. It needs to be finalized first.';
        case 'paid':
            throw 'The invoice is already paid.';
        case 'void':
            throw 'The invoice is void.';
        default: // open or uncollectible
            // do nothing
    }
    if (invoiceObj.collection_method !== 'send_invoice') {
        // collection_method が send_invoice でない場合は、Stripe の仕様で請求書をメール送付できない
        throw 'The collection method of the invoice is not send_invoice.';
    }
    const customerId = invoiceObj.customer;
    const paymentIntentId = invoiceObj.payment_intent;
    return {customerId, paymentIntentId};
}

/**
  * 顧客をチェックし、顧客のメールアドレスを返す
  * - 顧客が削除済みの場合、エラー
  * - 顧客のメールアドレスが設定されていない場合、エラー
  * @param {String} oauth 認証設定
  * @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"
        .get(apiUri);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        engine.log(responseStr);
        throw `Failed to retrieve customer. status: ${status}`;
    }
    const customerObj = JSON.parse(responseStr);
    if (customerObj.deleted) {
        throw 'The customer is deleted.';
    }
    const customerEmail = customerObj.email;
    if (customerEmail === null) {
        // 顧客のメールアドレス以外に「請求先メールアドレス」もダッシュボードからは設定できるが、API では取得不可
        // 「請求先メールアドレス」の設定有無によらず、顧客のメールアドレスが設定されていない場合はエラーにする
        throw "The customer's email is not set. Update the customer or send the invoice from Stripe dashboard.";
    }
    return customerEmail;
}

/**
  * 請求書を更新し、支払方法をカードのみにする
  * カード以外の支払方法があると、支払オブジェクトの setup_future_usage を設定できずエラーになる場合があるため
  * @param {String} oauth 認証設定
  * @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"
        .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 `Failed to update invoice. status: ${status}`;
    }
}

/**
  * 支払オブジェクトを更新し、
  * - 今後の支払いのために支払方法が保存されるようにする
  * - 領収書送付先メールアドレスを設定する
  * @param {String} oauth 認証設定
  * @param {String} paymentIntentId 支払オブジェクトの ID
  * @param {boolean} sendReceipt 領収書をメール送付するかどうか
  * @param {String} customerEmail 顧客のメールアドレス
  */
function updatePaymentIntent(auth, paymentIntentId, sendReceipt, customerEmail) {
    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"
        .formParam('setup_future_usage', 'off_session') // 今後のオフセッション支払いのために支払方法を保存
        .formParam('receipt_email', receiptEmail)
        .post(apiUri);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        engine.log(responseStr);
        throw `Failed to update payment intent. status: ${status}`;
    }
}

/**
  * 請求書をメール送付する
  * @param {String} oauth 認証設定
  * @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"
        .post(apiUri);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        // 顧客のメールアドレスが未設定の場合でもここではエラーにならず、レスポンスからも送信先はわからない
        engine.log(responseStr);
        throw `Failed to send invoice. status: ${status}`;
    }
}

    
%d bloggers like this: