スプレッドシートのステータスを変えた瞬間にPDFを自動作成する仕組み|朝バッチと編集時トリガーの使い分けと、空白PDFになる落とし穴
スプレッドシートのステータスを変えた瞬間にPDFを自動作成する仕組み|朝バッチと編集時トリガーの使い分けと、空白PDFになる落とし穴
受注や依頼を管理しているスプレッドシートで、ステータスを「依頼」に変えたら、その行の内容で指示書や発注書のPDFがすぐ出てほしい。この要望への答えは、Google Apps Script(GAS)の「インストーラブルな編集時トリガー」でステータス列の変更だけを拾い、HTMLをPDFに変換してGoogleドライブへ保存し、そのリンクをシートに書き戻す構成です。
結論から書きます。ポイントは3つです。1つ目、関数名をonEditにするだけの簡易トリガーではなく、インストーラブルトリガーで登録する(ドライブ保存とダイアログ表示には認可が要る)。2つ目、PDFの作り方は「HTMLをPDFに変換」と「シートをPDFに書き出し」の2方式があり、どちらが正しく出るかは環境で変わるので、採用前に同じデータで両方出して比べる。3つ目、即時トリガーを入れても、毎朝のバッチ処理は消さずに保険として残す。
この記事では、弊社graciautoが、自社工場で革製品を作り店舗とネットショップで販売しているメーカーのEC受注管理で、4つの販売チャネルの受注を1枚のスプレッドシートに集め、ステータス変更から数秒で製造指示書のA5 PDFが出るようにした実例をもとに、構成と手順、判断基準をまとめます。
先に結論|仕組みの全体像
| 工程 | 何が起きるか | 担当 |
|---|---|---|
| 1 | 担当者がチャネル別シートのステータス列を「製造依頼」に変える | 人 |
| 2 | 編集時トリガーが発火。対象シート・対象列・1セルだけの編集かを判定 | GAS |
| 3 | 行の必須項目(正品番)を検証し、依頼リストに同じ注文が無いか照合 | GAS |
| 4 | 指示書ID(NS09-0001形式)を採番し、依頼リストへ転記 | GAS |
| 5 | 行データからHTMLを組み立て、PDFに変換してドライブの指定フォルダへ保存 | GAS |
| 6 | PDFリンクと指示書IDを書き戻し、ステータスを「製造依頼済み」に更新。画面右下に完了通知 | GAS |
| 7 | 翌朝のバッチが「製造依頼のまま残った行」だけを回収 | バッチ |
担当者の操作はプルダウンを1回変えるだけです。数秒後にステータスが「製造依頼済み」に変わり、依頼リストにリンク付きの行が増えていれば完了です。
朝バッチと即時トリガーはどう使い分けるか
「毎朝7時に前日分をまとめて処理する」バッチと、「ステータスを変えた瞬間に動く」トリガーは、どちらか一方を選ぶものではありません。役割が違います。
| 朝バッチ | 編集時トリガー | |
|---|---|---|
| 向いている処理 | メール取り込み・マスタ照合・在庫突合など、外部データを大量に読む処理 | 1行を対象に「今すぐ紙が要る」処理 |
| 実行環境 | ローカルPCやサーバー(時間制限が緩い) | GAS(1回の実行は6分まで) |
| 失敗したとき | ログを見て再実行 | 画面に通知して、ステータスを元に戻す |
| 位置づけ | データ取り込みの正 | 補助。ただし採番の正はこちら |
判断基準は「人が待つかどうか」です。受注メールを読み込んで品番をマスタに当てる処理は、前日分がまとまってから走ればよく、誰も画面の前で待ちません。一方、店舗で在庫を確認して「在庫がないので工場に作ってもらう」と決めた瞬間は、担当者が指示書を印刷して工場へ渡したい場面です。翌朝まで待たせると、その間に電話やLINEで伝えることになり、二重管理が始まります。
即時トリガーを入れたあとも、朝バッチは消しません。GASが何らかの理由で動かなかった行(ステータスが「製造依頼」のまま残っている行)を翌朝に回収させ、注文番号・品番・色・サイズの組み合わせで照合して二重転記を防ぎます。採番だけはGASを正とし、バッチ側はGASが振った番号をそのまま使います。逆に、多数の帳票をまとめて出す処理はバッチ側に置きます。その設計は店舗ごとの月次レポート作成を自動化するに書いています。
実例|4チャネルの受注から製造指示書が数秒で出るまで
前提となる台帳の作りは次のとおりです。
- 販売チャネルは楽天・Shopify・Yahoo!ショッピング・Amazonの4つ。受注メールを毎朝7時のバッチで読み込み、チャネル別の4シート(各30列)に1行ずつ追加する
- ステータスはプルダウン。未対応/在庫確認中/発送準備/発送完了/製造依頼/製造依頼済み/キャンセル
- 「製造依頼リスト」シートに、指示書ID・発注日・注文番号・商品コード・商品名・色・サイズ・数量・工場・工程・メモ・PDFリンク・印刷チェックの列
- 指示書はA5縦1枚。紙の指示書と同じ7要素(タイトル帯、チャネルと注文番号、メモ枠、発注日・完成日・工場・指示書ID、商品コードと商品名、サイズ・色・数量・標準価格、検品チェックリスト)
受注の集約側の設計はネットショップの受注を1枚のスプレッドシートに集約する設計に、4チャネルの品番をそろえる考え方は楽天・Amazon・Yahoo!・自社ECの受注を1つにまとめる方法に書いています。本稿はその上に載せた即時処理の部分です。
設置後の動作確認は、実データの1行で次の一周を行いました。
- 楽天シートの1行でステータスを「製造依頼」にする。数秒で指示書ID「NS09-0001」が入り、依頼リストに行が増え、PDFリンクが書き込まれ、ステータスが「製造依頼済み」に変わり、行が黄色になる
- 生成されたPDFを開く。楽天の備考欄に書かれていたラッピング指定がメモ枠に印字されている
- 依頼リストの「印刷」チェックを入れる。「指示書を開く」ダイアログが出て、チェックは自動で外れる
- 同じ行のステータスを「発送完了」にする。実発送日に当日の日付が入り、行がグレーになる
確認後、テストに使った行と依頼リストの行、ドライブのPDFは元に戻しています。このとき、API経由での書き戻しには編集時トリガーが反応しないので、テストの後始末を安全に行えます。
実装の手順|6ステップ
1. インストーラブルトリガーで登録する
関数名をonEditにするだけの簡易トリガーは、ドライブへの保存やダイアログの表示ができません。認可が付かないためです。Apps Scriptの画面でトリガーを追加し、「実行する関数=自作の関数」「イベントのソース=スプレッドシートから」「イベントの種類=編集時」で登録し、認可画面を通します。
2. 入口で「何もしない条件」を先に書く
編集時トリガーはセルを触るたびに動くので、入口で対象外を弾きます。
function onEditInstalled(e) {
if (!e || !e.range) return;
// 複数セルの貼り付けは対象外
if (e.range.getNumRows() !== 1 || e.range.getNumColumns() !== 1) return;
var sheet = e.range.getSheet();
var row = e.range.getRow(), col = e.range.getColumn();
if (row < 2) return; // 見出し行
if (CHANNEL_SHEETS.indexOf(sheet.getName()) < 0 || col !== COL_STATUS) return;
if (e.value === '製造依頼') handleRequest_(sheet, row, e);
else if (e.value === '発送完了') handleShipped_(sheet, row);
}
対象シート・対象列・1セルだけ、の3条件を通った編集だけが本処理に進みます。処理全体をtry/catchで囲み、例外はトースト通知に出します。
3. ロックを取り、必須項目を検証する
複数の担当者が同時にステータスを変えることがあるので、スクリプトロックを取ってから採番します(今回は最大20秒待ち)。ロックが取れなければ通知を出し、ステータスを元の値に戻します。必須項目(正品番)が空の行も、ここで弾いてステータスを戻します。品番が確定していない行を「要確認」のまま止められることが、あとで効きます。
4. 採番と転記
指示書IDは「NS+月2桁+連番4桁」。依頼リストの同月の最大値に1を足します。転記の前に、注文番号・商品コード・色コード・サイズの組み合わせで既存行を探し、あれば新しい行は作らず既存IDを使います。同じ注文で二度ステータスを変えても行は増えません。
5. PDFを作ってドライブへ保存する
HTMLをPDFに変換する方式では、GAS側は次の2行で済みます。
var blob = Utilities.newBlob(html, 'text/html', sid + '.html').getAs('application/pdf');
var file = DriveApp.getFolderById(FOLDER_ID).createFile(blob.setName(sid + '.pdf'));
用紙サイズはHTML側の @page { size: 148mm 210mm; margin: 0; } で指定します。保存前に同名ファイルがフォルダにあればそのリンクを返すようにしておくと、再実行しても重複しません。GASは認可した人のアカウントで動くので、ファイルの所有者はその人になります。サービスアカウントで起きがちな「保存容量が無くてアップロードできない」問題も起きません。
6. 書き戻しと通知
指示書IDとステータスをシートに戻し、PDFリンクを依頼リストに書き、画面右下のトースト通知で「NS09-0001 を転記しました・指示書PDF生成済み」と出します。PDF生成だけは別のtry/catchで囲み、失敗しても転記は残す設計にします。リンクが空欄の行は翌朝のバッチが埋めます。
空白PDFになる落とし穴|PDFの作り方は2方式を実機で比べる
GASでスプレッドシートの内容をPDFにする方法は2つあります。
| 方式 | 作り方 | 長所 | 注意点 |
|---|---|---|---|
| HTML変換 | HTMLを組み立ててgetAs('application/pdf') | コードだけで完結。@pageで用紙サイズを指定できる | フォントや細かい余白は変換エンジン任せ |
| シート書き出し | 隠しテンプレートシートに値を差し込み、export?format=pdfのURLをOAuthトークン付きで取得 | レイアウトをシート上で目視調整できる | URLパラメータが環境によって効かないことがある |
どちらが正しく出るかは、事前には分かりません。GASのPDF変換はローカルで再現できないためです。そこで、設置手順に「同じテストデータで両方式のPDFをドライブに出す関数を1回実行し、承認済みの見本と並べて比べてから採用方式を決める」工程を入れます。
今回の環境でこの比較を行うと、シート書き出し方式は真っ白な1ページ(1KB弱)になりました。export URLの size=a5 がこの環境では効かず、内容が描画されなかったためです。HTML変換方式は見本とほぼ同一(注文番号の折り返しが1行になる程度)だったので、そちらを採用しました。
補足すると、シート書き出し方式そのものが使えないわけではありません。同じexport URLでも、A4指定と scale=4(ページに合わせる)を組み合わせた別案件の帳票PDF化では、1シート1ページで正常に出ています。効くパラメータの組み合わせが環境と用紙で変わる、と理解して、採用前の実機比較を省かないことが対策です。HTML変換で文字がはみ出す・切れる場合の検出方法はHTMLから作ったPDFで文字が切れて消えるときにまとめています。
起こりうる失敗と予防
| 起こりうること | 予防策 |
|---|---|
| 簡易トリガーで登録して「承認が必要です」で止まる | インストーラブルトリガーで登録し、認可を通す |
| PDF生成の失敗で転記まで巻き戻る | 転記とPDF生成のtry/catchを分ける。PDFだけ失敗したらリンク空欄で残し、翌朝バッチで補完 |
| 同時操作で同じ番号が2つ振られる | スクリプトロック。取れなければステータスを戻して再操作を促す |
| 同じ注文で二度依頼して行が増える | 注文番号+品番+色+サイズで既存行を照合 |
| 自動処理(APIやバッチ)からの書き込みでトリガーが動かない | 仕様として理解する。人の操作だけに反応するので、自動処理側は自分で転記まで行う |
| 空白のPDFが本番で出続ける | 採用前に2方式を同じデータで出して見本と比較。採用後もリンク先を開いて中身を確認する |
| トリガーが止まっていることに気づかない | 朝バッチが「製造依頼のまま」の行を回収し、ログに件数を残す |
GASのトリガーが止まる典型的な原因(権限・実行時間・オーナー変更)はClaudeで作った業務GASが突然止まるに、「成功と表示されているのに反映されていない」状態の見つけ方は自動処理が「成功」と出ているのに反映されないときに書いています。
進捗は「ツールを増やさない」で見せる
即時処理を入れると、次に「進捗をカレンダーで見たい」という話が出ます。今回は採用しませんでした。確認するツールを増やしても現場は見ないからです。代わりに、ステータスに応じて行の色を変え(発送完了=グレー、発送準備=緑、製造=黄、キャンセル=薄赤と取り消し線)、まとめシートの左上に「未発送3日超:N件」のカウンタを置きました。全受注は必ず「発送完了」か「キャンセル」で終わる、途中で止まった行は放っておくと勝手に目立つ、という原則を1枚の中で成立させます。
よくある質問
Q. スプレッドシート以外にツールを入れずにできますか
できます。必要なのはスプレッドシートに紐づくGASと、Googleドライブの保存先フォルダだけです。外部サービスとの連携もAPI料金も発生しません。
Q. ステータスを変えてからPDFが出るまでどのくらいかかりますか
今回の構成で数秒です。行の読み取り、採番、HTML組み立て、PDF変換、ドライブ保存、書き戻しをすべて1回の実行で行っています。GASの1回の実行は最大6分なので、この用途では余裕があります。
Q. 自分で作れますか
対象シートと列が決まっていて、PDFのレイアウトが1種類なら、この記事の6ステップで作れます。複数の担当者が同時に触る、朝のバッチ処理と併存させる、失敗時にステータスを戻す、といった条件が加わると、ロックと照合の設計が必要になるので、制作会社に相談する方が早いです。
まとめ
- ステータス変更でPDFを出すなら、インストーラブルな編集時トリガーで対象シート・対象列・1セルの編集だけを拾う
- 採番の前にスクリプトロックを取り、必須項目の検証と既存行の照合で二重登録を防ぐ
- PDFはHTML変換とシート書き出しの2方式。採用前に同じデータで両方出して見本と比べる。環境によってはシート書き出しが空白になる
- 転記とPDF生成のtry/catchは分け、PDFだけ失敗しても転記は残す
- 朝バッチは消さず、「依頼のまま残った行」の回収役として残す。採番の正はGAS側
- 進捗の見える化はツールを足さず、行の色分けとカウンタで済ませる
弊社では、受注メールの取り込みからスプレッドシートへの集約、ステータス操作による指示書PDFの即時発行、朝バッチとの併存設計まで一式で対応しています。「シートは作ったが、そこから先が手作業のまま」という方は、お問い合わせからご相談ください。