株式会社WR

株式会社WR

WEB TOTAL CONSULTING

GASでスプレッドシートをPDF出力——請求書自動生成の実装
ブログ一覧へ
技術ブログ

GASでスプレッドシートをPDF出力——請求書自動生成の実装

Google スプレッドシートのテンプレートをGASでPDF変換し、Gmailで自動送信する請求書発行システムの作り方を解説します。月次バッチで全顧客に一括送信も可能です。

GASでPDF出力——ビジネス文書の自動化

Google Apps ScriptのDocsApp・DriveAppを組み合わせると、Googleスプレッドシートのデータから請求書・領収書・見積書などのPDFを自動生成して、指定のフォルダに保存したりメールで送ったりすることができます。


基本的な仕組み

スプレッドシート(データ)
      ↓
GAS でGoogleドキュメントのテンプレートをコピー
      ↓
テンプレート内の{{プレースホルダー}}を置換
      ↓
PDFに変換
      ↓
Googleドライブに保存 or メール添付で送信

テンプレートの準備

Googleドキュメントで請求書テンプレートを作成し、プレースホルダーを挿入します。

{{invoice_number}}  ← 請求書番号
{{client_name}}     ← 宛先
{{issue_date}}      ← 発行日
{{due_date}}        ← 支払期限
{{subtotal}}        ← 小計
{{tax}}             ← 消費税
{{total}}           ← 合計

GASの実装

const TEMPLATE_ID   = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // テンプレートのドキュメントID
const OUTPUT_FOLDER = 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy';    // 出力先フォルダID

/**
 * スプレッドシートから請求書PDFを生成する
 * @param {number} row - スプレッドシートのデータ行(1-indexed、ヘッダーを除く)
 */
function generateInvoice(row) {
    const sheet = SpreadsheetApp.getActiveSpreadsheet()
                                 .getSheetByName('請求データ');
    const data  = sheet.getRange(row + 1, 1, 1, 10).getValues()[0];

    const invoiceData = {
        invoice_number: data[0],
        client_name:    data[1],
        issue_date:     Utilities.formatDate(new Date(data[2]), 'Asia/Tokyo', 'yyyy年MM月dd日'),
        due_date:       Utilities.formatDate(new Date(data[3]), 'Asia/Tokyo', 'yyyy年MM月dd日'),
        subtotal:       data[4].toLocaleString(),
        tax:            data[5].toLocaleString(),
        total:          data[6].toLocaleString(),
        description:    data[7],
    };

    // テンプレートをコピー
    const template = DriveApp.getFileById(TEMPLATE_ID);
    const folder   = DriveApp.getFolderById(OUTPUT_FOLDER);
    const docName  = `請求書_${invoiceData.invoice_number}_${invoiceData.client_name}`;
    const copy     = template.makeCopy(docName, folder);

    // コピーを開いてプレースホルダーを置換
    const doc  = DocumentApp.openById(copy.getId());
    const body = doc.getBody();

    Object.entries(invoiceData).forEach(([key, value]) => {
        body.replaceText(`{{${key}}}`, value);
    });

    doc.saveAndClose();

    // PDFに変換
    const pdfBlob = copy.getAs('application/pdf').setName(`${docName}.pdf`);
    const pdfFile = folder.createFile(pdfBlob);

    // 元のドキュメントを削除(PDFのみ残す)
    copy.setTrashed(true);

    console.log(`PDF生成完了: ${docName}.pdf`);
    return pdfFile;
}

一括生成とメール送信

/**
 * 未送付の請求書を全て生成してメールで送信
 */
function sendAllPendingInvoices() {
    const sheet = SpreadsheetApp.getActiveSpreadsheet()
                                 .getSheetByName('請求データ');
    const data  = sheet.getDataRange().getValues();

    let sentCount = 0;

    for (let i = 1; i < data.length; i++) {
        const status     = data[i][8]; // I列:送付状況
        const clientEmail = data[i][9]; // J列:送付先メール

        if (status !== '未送付' || !clientEmail) continue;

        try {
            const pdfFile = generateInvoice(i);
            const pdfBlob = pdfFile.getBlob();

            // メール送信
            GmailApp.sendEmail(
                clientEmail,
                `【ご請求】株式会社WR からの請求書 No.${data[i][0]}`,
                `${data[i][1]} 御中\n\n請求書をPDFで添付いたします。\nご確認のほどよろしくお願いいたします。\n\n株式会社WR\n代表取締役 土田昇`,
                {
                    attachments: [pdfBlob],
                    name:        '株式会社WR',
                }
            );

            // ステータスを更新
            sheet.getRange(i + 1, 9).setValue('送付済');
            sheet.getRange(i + 1, 11).setValue(new Date());
            sentCount++;

            // API制限対策
            Utilities.sleep(1000);

        } catch (error) {
            console.error(`行${i + 1}の処理でエラー: ${error.message}`);
            sheet.getRange(i + 1, 9).setValue(`エラー: ${error.message}`);
        }
    }

    console.log(`${sentCount}件の請求書を送信しました`);
    Browser.msgBox(`${sentCount}件の請求書を送信しました`);
}

月次請求書の自動化

/**
 * 毎月末に自動で請求書を生成する
 */
function generateMonthlyInvoices() {
    const today    = new Date();
    const lastDay  = new Date(today.getFullYear(), today.getMonth() + 1, 0).getDate();

    // 月末だけ実行
    if (today.getDate() !== lastDay) return;

    // サービス利用データを集計して請求データを作成
    const billingData = calculateMonthlyBilling();

    billingData.forEach(client => {
        // 請求データをスプレッドシートに追記
        addInvoiceRow(client);
    });

    // 請求書を生成してメール送信
    sendAllPendingInvoices();

    // Slackに完了通知
    sendSlackNotification(
        `月次請求書を${billingData.length}件送信しました(${today.toLocaleDateString('ja-JP')})`
    );
}

まとめ

GASによるPDF自動生成は、Googleドキュメントのテンプレート・DriveApp・GmailAppを組み合わせることで、追加コストゼロで実現できます。弊社では月次請求書の自動生成・送付をこの仕組みで運用しており、毎月の手作業を大幅に削減しています。

業務自動化ツールの開発についてはお気軽にご相談ください。

Category 技術ブログ

Related Posts

関連記事

開発・技術のご相談はお気軽に

お見積りは無料です。まずはお気軽にご相談ください。

お問い合わせ →