毎月末に請求書を手作業で作っていて、「これは絶対に自動化できる」と思ったので作りました。
Googleスプレッドシートにデータを入力してボタンを押すだけで、取引先ごとに請求書PDFを生成し、Gmailの下書きを作成します。確認してから送信ボタンを押す、というフローです。
コードはMITライセンスで全公開しています。
🔗 mamagotolab/gas-invoice-automation
できること
- スプレッドシートの請求データから請求書PDFを自動生成(HTMLベース・テンプレート不要)
- 取引先ごとにGmailの下書きを作成(PDF添付・本文自動生成)
- 確認後にまとめて自動送信するメニューも用意
- 複数品目を1枚の請求書にまとめる(同じ請求書番号でグルーピング)
- 小計・消費税(10%)・合計の自動計算
- 全件バリデーションを処理前に実施(1件でもエラーがあれば何も始めない)
- 処理済みフラグの自動記録(二重送付防止)
-
initSheets()で初期シートとサンプルデータを自動生成
導入手順
- Googleスプレッドシートを新規作成
- メニュー 拡張機能 → Apps Script を開く
-
Code.gsの中身を貼り付けて保存 - スプレッドシートを再読み込みすると 「請求書ツール」 メニューが表示される
- 「① 初期セットアップ(サンプル作成)」 を実行
- 「設定」シートに自社情報を入力して完成
Googleドキュメントのテンプレートもフォルダも不要です。スプレッドシート1つで動きます。
処理フロー
「② 請求書を作成(Gmail下書き)」を押す
↓
設定シートと全請求データをバリデーション(1件でもNGなら中止)
↓
請求書番号でグルーピング(同番号の複数行 → 1枚の請求書)
↓
取引先ごとにHTML請求書を生成 → PDF変換
↓
Gmail下書きを作成(PDF添付)
↓
「送信済み」フラグを記録
確認後に「③ 請求書を送信(自動)」を押すと一括送信できます。
スプレッドシートの列構成
| 列 | 項目 | 備考 |
|---|---|---|
| A | 請求書番号 | 同じ番号の行が1枚の請求書にまとまる |
| B | 発行日 | 例:2026-06-30 |
| C | 取引先名 | |
| D | 宛先メール | |
| E | 品目 | |
| F | 数量 | |
| G | 単価(税抜) | |
| H | ステータス | 自動更新 |
| I | 処理日時 | 自動更新 |
「初期セットアップ」を実行するとサンプルが入った状態で作られるので、そのまま書き換えて使えます。
コードの解説
設計の軸:「下書き作成」がデフォルト
function createInvoiceDrafts() {
processInvoices_(false); // false = 下書き作成
}
function sendInvoices() {
const ui = SpreadsheetApp.getUi();
const res = ui.alert(
'確認',
'請求書を取引先へ自動送信します。よろしいですか?\n(不安な場合は「請求書を作成(Gmail下書き)」をおすすめします)',
ui.ButtonSet.OK_CANCEL
);
if (res !== ui.Button.OK) return;
processInvoices_(true); // true = 送信
}
送信は別メニュー+確認ダイアログの2ステップにしています。請求書のような「間違えたら困る」処理は、自動化するほど事故の影響が大きくなるので、人が目視で確認する余地を必ず残します。
処理前の一括バリデーション
function processInvoices_(send) {
const config = readConfig_();
const invoices = groupByInvoice_(dataSheet);
// 処理を始める前に全件検証
const errors = validateInvoices_(invoices, config);
if (errors.length > 0) {
ui.alert('入力エラー', '処理を中止しました。以下を修正してください。\n\n' + errors.join('\n'), ui.ButtonSet.OK);
return;
}
// ← ここから先は全件OKが保証されている
Object.keys(invoices).forEach(function (no) { /* PDF生成・メール */ });
}
バリデーションは処理を始める前にまとめて実行します。「3件目でエラーが出て1〜2件目だけ下書きが作られた」という中途半端な状態を防ぎます。チェック内容は設定シートの必須項目、メールアドレスの形式、品目の空白、数量のゼロ以下など。
function validateInvoices_(invoices, config) {
const errors = [];
const required = ['自社名', '住所', '振込先'];
required.forEach(function (key) {
if (!config[key]) errors.push('・「設定」シートの『' + key + '』が空です');
});
const emailRe = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
Object.keys(invoices).forEach(function (no) {
const inv = invoices[no];
if (!inv.client) errors.push('・' + no + ':取引先名が空です');
if (!emailRe.test(inv.email)) errors.push('・' + no + ':宛先メールが不正です(' + inv.email + ')');
inv.items.forEach(function (it) {
if (!it.item) errors.push('・' + no + ':品目が空の行があります');
if (it.qty <= 0) errors.push('・' + no + ':数量が0以下の行があります(' + it.item + ')');
});
});
return errors;
}
請求書番号でのグルーピング
function groupByInvoice_(sheet) {
const values = sheet.getRange(2, 1, last - 1, COL.processedAt).getValues();
values.forEach(function (row, i) {
const no = String(row[COL.invoiceNo - 1]).trim();
if (!no) return;
if (!invoices[no]) {
invoices[no] = { no, client, email, items: [], rows: [] };
}
invoices[no].items.push({ item, qty, unitPrice });
invoices[no].rows.push(i + 2);
});
}
同じ請求書番号の行を1枚にまとめます。INV-001 が3行あれば、品目3つの請求書が1通作られます。行を削除せず「番号だけ変える」で品目を追加・分割できるのが使いやすいポイントです。
HTMLからPDFを生成(テンプレートファイル不要)
const html = buildInvoiceHtml_(config, inv);
const pdf = Utilities.newBlob(html, 'text/html', '請求書_' + no + '.html')
.getAs('application/pdf')
.setName('請求書_' + no + '.pdf');
GASの Blob.getAs('application/pdf') でHTMLをPDFに変換しています。Googleドキュメントのテンプレートを用意する必要がないので、導入の手間がゼロです。レイアウトは buildInvoiceHtml_() の中のHTMLを直接編集して変えられます。
動作環境・制限事項
- GASのメール送信上限:無料Googleアカウントで1日100通(受信者数ベース)、Google Workspaceで1,500通
- GASの実行時間上限:1回6分。大量処理の場合は請求書番号で分割実行してください
-
PDFのフォント:
Utilities.newBlob経由のPDFはGoogleのサーバーサイドでレンダリングされるため、日本語フォントはシステム依存です。フォントにこだわる場合はGoogleドキュメントテンプレート方式に切り替えてください
カスタマイズポイント
よくある拡張:
-
インボイス制度対応:
buildInvoiceHtml_()のHTMLに登録番号・税率区分の行を追加するだけ - 支払期限:設定シートの「支払期限(発行日から日数)」で変更できます(デフォルト30日)
-
Google Driveへの保存:
DriveApp.getFolderById(id).createFile(pdf)を追加すれば保存できます -
Slack通知:送信完了後に
UrlFetchApp.fetch()でIncoming Webhookを叩く
おわりに
このツールを作ったきっかけは「毎月末に同じ作業を繰り返すこと」への違和感でした。請求書を1枚ずつ手で作るのは難しくないですが、ミスが許されない緊張感だけが積み重なっていく。それをなくしたかった。
コードはMITライセンスで公開しているので、自由に使って、改造して、壊してもらって構いません。IssueやPRも歓迎です。
カスタマイズや業務フローとの統合(会計ソフト連携・督促メール自動化・入金消込など)については個別に対応しています。
🔗 コード:mamagotolab/gas-invoice-automation
🔗 開発ラボ:mamagotolab.com