毎月末になると、先月の請求書をコピーして取引先名と金額だけ書き換え、1件ずつPDFに変換してドライブへ保存する作業に時間を取られていないでしょうか。
件数が数件のうちは手作業でも回りますが、取引先が増えるほど書き換え漏れや金額の転記ミスが起きやすくなります。
Google Apps Script(Googleスプレッドシートに付属するスクリプト環境)でテンプレートシートに値を差し込み、請求書PDFを一括生成する方法を整理しています。
コード全文と、ドライブへの保存手順まで合わせて紹介する内容です。
Google Apps Scriptでの請求書自動作成が向くケース(請求書SaaSとの使い分け)
この方法が向くのは、月あたりの発行件数が数件から数十件程度で、入金管理までは求めていない事業者です。
| Google Apps Scriptでの自動作成 | 請求書SaaS | |
|---|---|---|
| 向く件数 | 月数件~数十件 | 月数十件以上 |
| 入金管理・催促 | 対応しない(別途管理が必要) | 標準機能で対応 |
| 追加費用 | かからない | 月額費用が発生する |
| 既存のスプレッドシート運用 | そのまま活かせる | 別システムへの移行が必要 |
入金状況の管理や取引先ごとの残高確認まで自動化したい場合は、請求書SaaSの導入を検討したほうが早く済みます。
すでにスプレッドシートで顧客リストや金額を管理していて、PDF化の手間だけをなくしたい場合は、この方法が候補です。
Google Apps Scriptでの自動化全体の進め方は、以下で整理しています。

準備するもの:請求書テンプレートシートと請求リスト
準備するシートは2枚です。
1枚目は請求書のレイアウトを作った『請求書テンプレート』シートで、会社名や金額を入れるセルをあらかじめ決めておきます。
2枚目は発行する請求書の件数分を1行ずつ並べた『請求リスト』シートで、取引先名・請求日・請求書番号・金額・摘要・処理済みフラグの列を用意する構成です。
経理業務全体の自動化の進め方は、以下で整理しています。

Google Apps Scriptで請求書PDFを自動生成する手順
テンプレートシートに1行分の値を差し込み、PDFとして書き出してからドライブへ保存する流れをスクリプトにします。
処理が終わった行には済みフラグを立てるため、途中で止めても再実行時に重複出力しません。
Step1. テンプレートに差し込み用のセルを決める
『請求書テンプレート』シートを開き、取引先名・請求日・請求書番号・金額・摘要を入れるセルを決めます。
今回はC3からC11の範囲に決めましたが、セルの位置はテンプレートのレイアウトに合わせて自由に変更してかまいません。
Step2. コードを貼り付ける(コード全文)
拡張機能からApps Scriptエディタを開き、以下をそのまま貼り付けます。
const TEMPLATE_SHEET_NAME = '請求書テンプレート';
const LIST_SHEET_NAME = '請求リスト';
const OUTPUT_FOLDER_ID = 'ここにドライブの保存先フォルダIDを入れる';
// 請求リストの列(A列から順に0,1,2...)
const LIST_COL = {
customerName: 0,
invoiceDate: 1,
invoiceNo: 2,
amount: 3,
description: 4,
status: 5,
};
// テンプレートシートの差し込み先セル
const TEMPLATE_CELL = {
customerName: 'C3',
invoiceDate: 'C4',
invoiceNo: 'C5',
amount: 'C10',
description: 'C11',
};
function createInvoicePdfs() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const templateSheet = ss.getSheetByName(TEMPLATE_SHEET_NAME);
const listSheet = ss.getSheetByName(LIST_SHEET_NAME);
const folder = DriveApp.getFolderById(OUTPUT_FOLDER_ID);
const rows = listSheet.getDataRange().getValues();
for (let i = 1; i < rows.length; i++) {
const row = rows[i];
if (row[LIST_COL.status] === '済') {
continue;
}
fillTemplate(templateSheet, row);
SpreadsheetApp.flush();
const pdfBlob = exportSheetAsPdf(ss, templateSheet);
const fileName = `請求書_${row[LIST_COL.customerName]}_${row[LIST_COL.invoiceNo]}.pdf`;
folder.createFile(pdfBlob).setName(fileName);
listSheet.getRange(i + 1, LIST_COL.status + 1).setValue('済');
}
clearTemplate(templateSheet);
}
function fillTemplate(sheet, row) {
sheet.getRange(TEMPLATE_CELL.customerName).setValue(row[LIST_COL.customerName]);
sheet.getRange(TEMPLATE_CELL.invoiceDate).setValue(row[LIST_COL.invoiceDate]);
sheet.getRange(TEMPLATE_CELL.invoiceNo).setValue(row[LIST_COL.invoiceNo]);
sheet.getRange(TEMPLATE_CELL.amount).setValue(row[LIST_COL.amount]);
sheet.getRange(TEMPLATE_CELL.description).setValue(row[LIST_COL.description]);
}
function exportSheetAsPdf(ss, sheet) {
const url = 'https://docs.google.com/spreadsheets/d/' + ss.getId() + '/export'
+ '?format=pdf&gid=' + sheet.getSheetId()
+ '&size=A4&portrait=true&fitw=true&gridlines=false&printtitle=false';
const response = UrlFetchApp.fetch(url, {
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
});
return response.getBlob();
}
function clearTemplate(sheet) {
Object.values(TEMPLATE_CELL).forEach((cell) => sheet.getRange(cell).clearContent());
} このコードが何をしているか
createInvoicePdfs が『請求リスト』を1行ずつ読み、済みフラグが立っていない行だけを処理します。
fillTemplate でその行の値をテンプレートシートへ書き込み、exportSheetAsPdf がテンプレートシートをPDF形式のURLで書き出してファイルとして受け取る仕組みです。
受け取ったPDFを指定フォルダへ保存したら済みフラグを立て、全行の処理が終わったら clearTemplate でテンプレートを空欄に戻す流れです。
自分のデータに合わせて変える場所
OUTPUT_FOLDER_IDにはPDFの保存先フォルダIDを入れます。
ドライブでフォルダを開いたときのURLの/folders/以降の文字列をそのまま貼り付けてください。TEMPLATE_CELLの各値はStep1で決めたセル番地です。
テンプレートのレイアウトが違えばここだけ書き換えます。LIST_COLの各値は『請求リスト』の列の並び順です。
A列が0、B列が1というように左から0始まりで数えます。
Step3. 1件でテスト実行する
『請求リスト』に1行だけデータを入れた状態で、Apps Scriptエディタから createInvoicePdfs を選んで実行します。
初回実行時は権限の承認画面が表示されるので、自分で作成したスクリプトであることを確認したうえで許可します。
実行が終わったら、テンプレートシートへの差し込みと指定フォルダへのPDF作成を目視で確認する流れです。
Step4. 保存先フォルダを確認する
テスト実行で問題がなければ、『請求リスト』に本番分の行を追加してから再度実行します。
処理済みの行には済みフラグが立つため、翌月以降は新しく追加した行だけが対象になります。
請求書PDF自動生成でよくあるエラーと対処
- 「対象のフォルダが見つかりません」と表示されるときは、
OUTPUT_FOLDER_IDに入れた文字列が間違っています。
ドライブのURLから/folders/以降だけを正しくコピーし直してください。 - 承認画面で「このアプリは確認されていません」と表示されても、自分で作成したスクリプトであれば、詳細を開いて許可を進めて問題ありません。
- PDFのレイアウトが崩れる場合は、テンプレートシートの印刷範囲設定がずれている可能性があります。
ファイルメニューの印刷設定で範囲と用紙サイズを確認してください。 - 2件目以降の値が反映されないときは、書き込み直後にPDF化して反映前の内容が出力されている可能性があります。
SpreadsheetApp.flush()を外していないか確認してください。
見積書の発行も自動化したい場合は、以下の想定ケースも参考になります。
請求書まわりの自動化について相談してみませんか?
「テンプレートの作り方が合っているか自信がない」「インボイス制度で必要な項目を整理してほしい」「請求業務全体を見直したい」
少しでもお心当たりがあれば、お気軽にご相談ください。
現在、Google Apps Scriptを使った業務自動化のお悩みをお伺いする 無料の個別相談 を実施しています。
よくある質問
Q. インボイス制度に対応した登録番号などはどう入れればいいですか?
登録番号や振込先などの固定項目は、テンプレートシート側にあらかじめ入力しておけば毎回そのまま出力されます。
記載すべき項目の判断は税理士等に確認してください。
Q. 一度に何件くらいまで処理できますか?
Google Apps Scriptには1回の実行につき6分までという仕様上の上限があります。
数十件程度なら1回の実行で収まりますが、数百件を超える場合は『請求リスト』を分けて複数回に分けて実行してください。
Q. 承認画面で止まってしまったのですが、どうすればいいですか?
初回実行時に表示される権限の承認画面で止まっている状態です。
自分で作成したスクリプトであれば、画面下部の詳細を開いて許可を進めれば実行が続けられます。