業務自動化

前日発注を自動化!GASで給食弁当の注文集計と仕入れ連絡を時短

飲食 の業務自動化レシピ
業種飲食
ツールGoogle Apps Script (GAS)
難易度★★☆ 中
設定時間約 90 分

給食弁当業では、電話・FAX・メールの注文を集計し、仕入れ先へ前日発注する作業が毎日発生します。GoogleフォームとGoogle Apps Script(GAS)を使えば、注文集計、発注メール、キャンセル待ち管理を一つの流れにまとめられます。小規模事業者が低コストで始める手順を紹介します。

⏱ 読了時間: 約14分(コード確認を含む)

🎯 この記事のポイント

編集長の見解: 給食弁当の注文管理は、売上と仕入れを支える重要な業務です。自動化すれば、転記ミスや確認漏れを減らせます。ただし、最初から全業務を置き換える必要はありません。まずは1日分の集計と発注メールから試し、現場に合う範囲で広げるのが現実的です。


🍱 給食弁当業者の注文管理の課題

給食弁当の現場では、注文管理に手間がかかります。特に前日発注は、正確さと速さの両方が必要です。ここでは、よくある課題を整理します。

複数経路に分散する注文の集約コスト

注文は、電話・FAX・メール・口頭などに分かれがちです。法人向けの給食受託や学校給食を扱う事業者では、複数の受付方法を併用することもあります。

注文経路集計時の問題点頻度
電話メモを台帳へ転記する必要がある毎日
FAX注文書の内容を手入力する必要がある毎日
メール件名や本文の形式がそろわない毎日
口頭(対面)記憶に頼るため確認が必要になる不定期

複数経路の注文を締切後に手作業でまとめると、担当者の負担が増えます。集計が昼食準備と重なる場合は、残業につながることもあります。

集計ミスが引き起こす仕入れ過多と不足

手作業では、数量の読み間違いや転記漏れが起こります。商品名の取り違えも、仕入れ数を誤る原因です。

失敗パターン: FAX注文の読み取りを誤ると、弁当を過剰に発注して廃棄ロスが発生します。反対に、発注数が足りなければ、提供遅延や代替メニューの案内が必要になる場合があります。自動化では、入力項目と商品名をそろえ、送信前に確認できる仕組みを用意します。

キャンセル待ち顧客への連絡漏れ

人気メニューでは、受付開始直後に注文枠が埋まることがあります。キャンセル待ちの対応では、次の作業が必要です。

担当者だけが管理していると、休みの日に連絡漏れが起きやすくなります。リストと状態を共有すれば、対応状況を確認しやすくなります。

前日発注の締切時間との戦い

給食弁当の仕入れは、前日発注が基本です。注文締切から仕入れ先の締切までに、集計と確認を終えなければなりません。

注文数が多い日や、直前に変更が入った日は、作業時間がさらに短くなります。次は、GASを使った自動化の全体像を確認します。


🔧 GASで作る自動化の全体像

Google Apps Script(GAS)は、Googleのサービスを自動化する仕組みです。JavaScriptを使って、Googleフォーム、スプレッドシート、Gmailなどを連携できます。

自動化の4つの柱

本記事では、次の4つを構築します。

柱処理内容頻度
①注文受付Googleフォームで注文を収集し、スプレッドシートへ保存随時
②注文集計商品別・日付別の数量を集計毎日
③前日発注メール集計結果を仕入れ先へ送信毎日
④キャンセル待ち管理待機者の登録と連絡状況を管理随時

システム構成のイメージ

[顧客] → Googleフォーム → スプレッドシート → GASで集計
                                                  ↓
[仕入れ先] ← 発注メール ← 集計結果を本文に整形
                                                  ↓
[キャンセル待ち顧客] ← 通知メール ← 待機リストを確認

必要なもの

必要なもの内容コスト
GoogleアカウントGmail、スプレッドシート、フォームを利用無料
Googleフォーム注文受付用フォーム無料
Googleスプレッドシート注文データの保存・集計無料
GAS(Google Apps Script)自動処理のスクリプト無料枠あり
仕入れ先のメールアドレス発注連絡の送信先-

ポイント: 個人向けGoogleアカウントでは、GASからのメール送信に1日100通までという上限があります。前日発注メールを数通送る運用なら、まず無料枠で試せます。送信数が多い場合は、Google Workspaceの利用も検討してください。

処理の流れ

時刻処理実行方法
随時顧客がGoogleフォームから注文顧客が操作
前日12:00注文締切フォームの受付を停止
前日12:05注文データを集計時間主導型トリガー
前日12:10発注メールを送信時間主導型トリガー
随時キャンセル待ちを確認編集または定期実行

なぜGASなのか

注文管理の自動化には、複数の選択肢があります。

方法初期費用月額費用難易度編集部の評価
GAS+Googleフォーム無料無料枠あり中小規模事業者の試行に適する
業務用受注管理システム数万円〜数千円〜低操作しやすいが比較が必要
カスタム開発数十万円〜保守費用高独自要件が多い事業者向け
Excel VBA無料無料中利用環境が限定される

GASは、初期費用を抑えてクラウド上で動かせます。まずは注文集計だけを自動化し、運用に慣れてから発注メールへ進む方法もあります。次は、フォームとスプレッドシートを準備します。


📝 ステップ1: Googleフォームとスプレッドシートの準備

ここでは、注文フォームの項目設計と、回答を保存するシートを準備します。フォームの項目は、後のコードが参照する列と一致させます。

注文フォームの項目設計

項目名フォームの種類設定例
お名前記述式山田太郎
会社名(任意)記述式株式会社サンプル
メールアドレス記述式taro@example.com
受け取り日日付選択2026年5月10日
商品名プルダウン日替わり弁当(税込600円)
数量プルダウン1〜50食
受け取り時間プルダウン11:30 / 12:00 / 12:30
備考記述式アレルギー対応希望など
キャンセル待ち希望ラジオボタンはい / いいえ

フォーム作成のポイント: 商品名と数量はプルダウンにします。自由記述では「のり弁」と「のり弁当」のような表記ゆれが起こり、集計が分かれるためです。

回答をスプレッドシートに保存する設定

  1. Googleフォームの編集画面を開く
  2. 「回答」タブをクリック
  3. スプレッドシートのアイコンをクリック
  4. 「新しいスプレッドシートを作成」を選択
  5. シート名を入力して作成

フォームの回答は、1行ずつスプレッドシートへ追加されます。

集計用シートとキャンセル待ち用シートの作成

シート名用途
フォームの回答 1フォームの回答を保存
集計GASが集計結果を出力
キャンセル待ち待機者を管理
送信ログメール送信履歴を記録

スプレッドシートの列構成

列項目名例
Aタイムスタンプ2026/05/09 9:00:00
Bお名前山田太郎
C会社名(任意)株式会社サンプル
Dメールアドレスtaro@example.com
E受け取り日2026/05/10
F商品名日替わり弁当
G数量3
H受け取り時間12:00
I備考-
Jキャンセル待ち希望はい / いいえ

列を後から追加・削除すると、コードの参照位置とずれる場合があります。運用前に項目を確定してください。次は、注文を集計するコードを作成します。


🤖 ステップ2: GASで注文を自動集計するスクリプト

ここでは、注文を商品別・日付別に集計します。列番号は、前のセクションで示した構成を前提にしています。

GASエディタの開き方

  1. スプレッドシートを開く
  2. 「拡張機能」→「Apps Script」をクリック
  3. GASエディタでコードを貼り付ける

注文データを読み込む基本コード

function getOrderData() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('フォームの回答 1');

  const lastRow = sheet.getLastRow();
  if (lastRow < 2) {
    return [];
  }

  const lastCol = sheet.getLastColumn();
  const dataRange = sheet.getRange(2, 1, lastRow - 1, lastCol);
  return dataRange.getValues();
}

getLastRow()とgetLastColumn()で、データ範囲を動的に取得します。

商品ごとの数量を集計するコード

function aggregateOrders(targetDate) {
  const orders = getOrderData();
  const summary = {};

  orders.forEach(function(order) {
    const orderDate = order[4];
    const productName = order[5];
    const quantity = Number(order[6]);

    if (!(orderDate instanceof Date)) {
      return;
    }

    const dateStr = Utilities.formatDate(orderDate, 'Asia/Tokyo', 'yyyy-MM-dd');
    if (dateStr !== targetDate) {
      return;
    }

    if (summary[productName]) {
      summary[productName] += quantity;
    } else {
      summary[productName] = quantity;
    }
  });

  return summary;
}

この関数は、指定した日付の注文だけを商品別に集計します。

商品名数量
日替わり弁当45
のり弁当30
カツ弁当22

集計結果をシートへ出力するコード

function writeSummaryToSheet(targetDate) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const summarySheet = ss.getSheetByName('集計');

  summarySheet.clearContents();
  summarySheet.getRange(1, 1, 1, 3).setValues([
    ['商品名', '数量', '受け取り日']
  ]);

  const summary = aggregateOrders(targetDate);
  const rows = Object.keys(summary).map(function(productName) {
    return [productName, summary[productName], targetDate];
  });

  if (rows.length > 0) {
    summarySheet.getRange(2, 1, rows.length, 3).setValues(rows);
  }

  const totalQuantity = Object.values(summary).reduce(function(a, b) {
    return a + b;
  }, 0);

  const totalRow = rows.length + 2;
  summarySheet.getRange(totalRow, 1, 1, 3).setValues([
    ['合計', totalQuantity, targetDate]
  ]);
}

集計対象日を判断するコード

function getTargetDate() {
  const now = new Date();
  const deadlineHour = 12;
  const deadlineMinute = 0;

  const currentHour = now.getHours();
  const currentMinute = now.getMinutes();

  const targetDate = new Date(now);

  if (
    currentHour > deadlineHour ||
    (currentHour === deadlineHour && currentMinute >= deadlineMinute)
  ) {
    targetDate.setDate(targetDate.getDate() + 1);
  }

  return Utilities.formatDate(targetDate, 'Asia/Tokyo', 'yyyy-MM-dd');
}

例えば、5月9日11時に実行すると5月9日、13時に実行すると5月10日を返します。実際の締切時刻に合わせて、コードとトリガーの設定をそろえてください。

編集長の見解: 自動化の要は、集計対象日を明確にすることです。締切時刻と対象日を先に決めておけば、担当者が毎回判断する必要がありません。導入時は、実際の日付を使ったテストで結果を確認してください。

メイン関数とトリガーの設定

function main() {
  const targetDate = getTargetDate();
  writeSummaryToSheet(targetDate);
  sendOrderEmail(targetDate);
}

トリガーは、次のように設定します。

設定項目値
実行する関数main
実行するデプロイHead
イベントのソース時間主導型
時間ベースのトリガー日ベースのタイマー
時刻を選択午後12時〜1時

トリガーの実行時刻には幅があります。締切が12時の場合は、12時05分以降に実行される設定を検討してください。次は、集計結果を発注メールに変換します。


📧 ステップ3: 仕入れ先への前日発注メール自動送信

集計結果をメール本文に整え、仕入れ先へ送信します。本番運用の前に、自分のメールアドレスでテストしてください。

集計結果をメール本文に整形するコード

function formatOrderEmailBody(targetDate, summary) {
  const dateParts = targetDate.split('-');
  const dateStr =
    dateParts[0] + '年' +
    Number(dateParts[1]) + '月' +
    Number(dateParts[2]) + '日';

  let body = '';
  body += 'お世話になっております。\n\n';
  body += dateStr + ' の弁当発注数量をご連絡いたします。\n\n';
  body += '【発注数量】\n';
  body += '-----------------------------\n';

  for (const productName in summary) {
    body += productName + ': ' + summary[productName] + '食\n';
  }

  body += '-----------------------------\n';
  body += '合計: ' +
    Object.values(summary).reduce(function(a, b) {
      return a + b;
    }, 0) + '食\n\n';
  body += 'ご確認のほど、よろしくお願いいたします。\n';
  body += '株式会社サンプル給食\n';
  body += '担当: 山田太郎\n';
  body += 'TEL: 03-1234-5678\n';

  return body;
}

仕入れ先へ自動送信するコード

function sendOrderEmail(targetDate) {
  const summary = aggregateOrders(targetDate);

  if (Object.keys(summary).length === 0) {
    Logger.log('注文データがありません。メールを送信しません。');
    return;
  }

  const body = formatOrderEmailBody(targetDate, summary);
  const recipient = 'supplier@example.com';
  const subject = '【発注】' + targetDate + ' の弁当発注数量';

  MailApp.sendEmail({
    to: recipient,
    subject: subject,
    body: body
  });

  writeSendLog(targetDate, recipient, subject);
}

複数の仕入れ先へ送る場合

function sendOrderEmailBySupplier(targetDate, summary) {
  const supplierConfig = {
    'supplier1@example.com': ['日替わり弁当', 'のり弁当'],
    'supplier2@example.com': ['カツ弁当']
  };

  for (const supplierEmail in supplierConfig) {
    const products = supplierConfig[supplierEmail];
    const supplierSummary = {};

    products.forEach(function(product) {
      if (summary[product]) {
        supplierSummary[product] = summary[product];
      }
    });

    if (Object.keys(supplierSummary).length === 0) {
      continue;
    }

    const body = formatOrderEmailBody(targetDate, supplierSummary);
    MailApp.sendEmail({
      to: supplierEmail,
      subject: '【発注】' + targetDate + ' の弁当発注数量',
      body: body
    });
  }
}

送信履歴を記録するコード

function writeSendLog(targetDate, recipient, subject) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const logSheet = ss.getSheetByName('送信ログ');

  if (logSheet.getLastRow() === 0) {
    logSheet.getRange(1, 1, 1, 5).setValues([
      ['送信日時', '対象日付', '送信先', '件名', 'ステータス']
    ]);
  }

  const lastRow = logSheet.getLastRow() + 1;
  logSheet.getRange(lastRow, 1, 1, 5).setValues([
    [new Date(), targetDate, recipient, subject, '送信済み']
  ]);
}

メール送信のテスト方法

  1. 本番用スプレッドシートをコピーする
  2. 送信先を自分のメールアドレスに変更する
  3. テストデータをフォームから入力する
  4. main()関数を手動実行する
  5. 集計結果と受信メールを確認する

重大な警告: テストなしで本番実行すると、誤った数量のメールを送るおそれがあります。フォームの列、商品名、数量、送信先、集計結果を順番に確認してください。本番トリガーは、テスト完了後に有効化します。

次は、キャンセル待ちの登録と連絡を自動化します。


⏳ ステップ4: キャンセル待ちリストの自動管理

キャンセルが発生したときに、待機者へ連絡する仕組みを作ります。待機順と状態をシートで管理すると、対応状況を共有できます。

キャンセル待ちリストの設計

列項目名例
A登録日時2026/05/09 9:30:00
Bお名前佐藤花子
Cメールアドレスhanako@example.com
D商品名日替わり弁当
E受け取り日2026/05/10
F数量2
G状態待機中 / 連絡済み / 確定
H連絡日時2026/05/09 15:00:00
I備考-

キャンセル待ち登録のコード

function registerCancellationWaitlist() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const formSheet = ss.getSheetByName('フォームの回答 1');
  const waitlistSheet = ss.getSheetByName('キャンセル待ち');

  const lastRow = formSheet.getLastRow();
  if (lastRow < 2) {
    return;
  }

  const values = formSheet
    .getRange(2, 1, lastRow - 1, formSheet.getLastColumn())
    .getValues();

  const waitlistLastRow = waitlistSheet.getLastRow();
  const existingEmails = [];

  if (waitlistLastRow >= 2) {
    const waitlistData = waitlistSheet
      .getRange(2, 3, waitlistLastRow - 1, 1)
      .getValues();

    waitlistData.forEach(function(row) {
      existingEmails.push(row[0]);
    });
  }

  values.forEach(function(order) {
    const waitlistFlag = order[9];
    const email = order[3];
    const productName = order[5];
    const orderDate = order[4];
    const quantity = order[6];
    const name = order[1];

    if (
      waitlistFlag === 'はい' &&
      existingEmails.indexOf(email) === -1
    ) {
      const newRow = waitlistSheet.getLastRow() + 1;
      waitlistSheet.getRange(newRow, 1, 1, 7).setValues([
        [new Date(), name, email, productName, orderDate, quantity, '待機中']
      ]);
      existingEmails.push(email);
    }
  });
}

キャンセル発生時の通知コード

function notifyCancellationWaitlist(
  productName,
  targetDate,
  cancelledQuantity
) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const waitlistSheet = ss.getSheetByName('キャンセル待ち');
  const lastRow = waitlistSheet.getLastRow();

  if (lastRow < 2) {
    Logger.log('キャンセル待ちリストが空です。');
    return;
  }

  const values = waitlistSheet
    .getRange(2, 1, lastRow - 1, 9)
    .getValues();

  let remainingQuantity = cancelledQuantity;

  values.forEach(function(row, index) {
    if (remainingQuantity <= 0) {
      return;
    }

    const status = row[6];
    const rowProduct = row[3];
    const rowDate = row[4];
    const rowEmail = row[2];
    const rowName = row[1];
    const rowQuantity = Number(row[5]);

    const sameDate =
      rowDate instanceof Date &&
      Utilities.formatDate(rowDate, 'Asia/Tokyo', 'yyyy-MM-dd') ===
        targetDate;

    if (
      status !== '待機中' ||
      rowProduct !== productName ||
      !sameDate
    ) {
      return;
    }

    const subject =
      '【キャンセル待ち繰り上げのご案内】' +
      productName + ' ' + targetDate;

    const body =
      rowName + ' 様\n\n' +
      'お世話になっております。株式会社サンプル給食です。\n\n' +
      'ご希望の「' + productName + '」(' + targetDate + ')に\n' +
      'キャンセルが発生しました。\n\n' +
      'ご注文を確定する場合は、以下のフォームからお申し込みください。\n' +
      'https://forms.gle/xxxxxxxxxx\n\n' +
      '24時間以内にご返信がない場合は、次の待機者へ案内します。\n\n' +
      'よろしくお願いいたします。\n' +
      '株式会社サンプル給食\n' +
      '担当: 山田太郎\n';

    MailApp.sendEmail({
      to: rowEmail,
      subject: subject,
      body: body
    });

    const rowNumber = index + 2;
    waitlistSheet.getRange(rowNumber, 7, 1, 2).setValues([
      ['連絡済み', new Date()]
    ]);

    remainingQuantity -= rowQuantity;
  });
}

繰り上がり確定処理

function confirmWaitlistOrder() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const formSheet = ss.getSheetByName('フォームの回答 1');
  const waitlistSheet = ss.getSheetByName('キャンセル待ち');

  const lastRow = formSheet.getLastRow();
  if (lastRow < 2) {
    return;
  }

  const lastOrder = formSheet
    .getRange(lastRow, 1, 1, formSheet.getLastColumn())
    .getValues()[0];

  const email = lastOrder[3];
  const productName = lastOrder[5];
  const orderDate = lastOrder[4];

  const waitlistLastRow = waitlistSheet.getLastRow();
  if (waitlistLastRow < 2) {
    return;
  }

  const waitlistData = waitlistSheet
    .getRange(2, 1, waitlistLastRow - 1, 9)
    .getValues();

  waitlistData.forEach(function(row, index) {
    const status = row[6];
    const rowEmail = row[2];
    const rowProduct = row[3];
    const rowDate = row[4];

    const sameDate =
      rowDate instanceof Date &&
      orderDate instanceof Date &&
      Utilities.formatDate(rowDate, 'Asia/Tokyo', 'yyyy-MM-dd') ===
        Utilities.formatDate(orderDate, 'Asia/Tokyo', 'yyyy-MM-dd');

    if (
      status === '連絡済み' &&
      rowEmail === email &&
      rowProduct === productName &&
      sameDate
    ) {
      const rowNumber = index + 2;
      waitlistSheet.getRange(rowNumber, 7).setValue('確定');
      waitlistSheet.getRange(rowNumber, 9).setValue('注文フォームから確定');
    }
  });
}

キャンセル待ち管理のトリガー

トリガー実行関数タイミング
時間主導型registerCancellationWaitlist1時間ごと
フォーム送信時confirmWaitlistOrderフォーム送信時

運用のポイント: キャンセル発生時にすぐ通知したい場合は、管理シートの編集を起点にします。キャンセルの入力者、商品名、数量、受け取り日を決めた列にそろえると、通知処理を安定させやすくなります。

次は、導入後に起こりやすい問題と対策を確認します。


⚠️ 編集部の警告: 失敗しがちな落とし穴

GASは便利ですが、設定を誤るとトラブルにつながります。導入前に、次の注意点を確認してください。

落とし穴1: GASの実行時間制限(6分)

GASには、1回の実行につき6分間という時間制限があります。大量データを一度に処理すると、制限を超えて終了する場合があります。

データ量処理時間の目安6分以内に収まるか
100件の注文数秒✅ おおむね問題なし
1,000件の注文数十秒✅ 構成による
10,000件の注文数分⚠️ 要検討
100,000件の注文数十分❌ 分割が必要

対策は次のとおりです。

function processOrdersInBatches() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('フォームの回答 1');
  const lastRow = sheet.getLastRow();
  const batchSize = 500;

  for (let startRow = 2; startRow <= lastRow; startRow += batchSize) {
    const endRow = Math.min(
      startRow + batchSize - 1,
      lastRow
    );

    const batchData = sheet
      .getRange(
        startRow,
        1,
        endRow - startRow + 1,
        sheet.getLastColumn()
      )
      .getValues();

    processBatch(batchData);
  }
}

落とし穴2: メール送信の誤送信

自動メールは、設定を誤ると誤った数量を送るおそれがあります。

対策: 本番用シートをコピーしてテスト環境を作り、送信先を自分のメールアドレスに変更してください。数量、送信先、件名、送信ログを確認してから、本番トリガーを有効にします。

手動実行時に確認画面を出す場合は、次のコードを使えます。

function mainWithConfirmation() {
  const ui = SpreadsheetApp.getUi();
  const response = ui.alert(
    '発注メール送信確認',
    '集計結果を仕入れ先へ送信します。よろしいですか?',
    ui.ButtonSet.YES_NO
  );

  if (response === ui.Button.YES) {
    main();
  } else {
    Logger.log('送信をキャンセルしました。');
  }
}

落とし穴3: フォームの締切と実行時刻のずれ

フォームの受付停止とGASの実行時刻がずれると、締切前後の注文を誤って扱う場合があります。

状況問題
受付停止前に回答が入る集計対象に含まれる
受付停止を忘れる締切後の注文が入る
締切と実行が同時刻対象範囲が不明確になる

フォームを自動で停止・再開する例です。

function closeOrderForm() {
  const form = FormApp.openById('フォームIDをここに入力');
  form.setAcceptingResponses(false);
}

function openOrderForm() {
  const form = FormApp.openById('フォームIDをここに入力');
  form.setAcceptingResponses(true);
}

トリガーは、次の順で設定します。

トリガー実行関数時刻
日ベースのタイマーcloseOrderForm12:00
日ベースのタイマーmain12:05
日ベースのタイマーopenOrderForm12:10

落とし穴4: メールの重複送信

複数のトリガーや手動実行が重なると、同じメールを複数回送ることがあります。送信ログで対象日付を確認し、送信済みなら処理を止めます。

function isAlreadySent(targetDate) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const logSheet = ss.getSheetByName('送信ログ');
  const lastRow = logSheet.getLastRow();

  if (lastRow < 2) {
    return false;
  }

  const logData = logSheet
    .getRange(2, 2, lastRow - 1, 1)
    .getValues();

  return logData.some(function(row) {
    return row[0] === targetDate;
  });
}

function sendOrderEmailWithDupCheck(targetDate) {
  if (isAlreadySent(targetDate)) {
    Logger.log(
      '対象日付 ' + targetDate + ' のメールは送信済みです。'
    );
    return;
  }

  sendOrderEmail(targetDate);
}

次は、料金や運用に関する質問に答えます。


❓ よくある質問

Q1. GASの利用料金はかかる?

GASは、個人向けGoogleアカウントでもGoogle Workspaceでも利用できます。メール送信数などに上限があるため、事業規模に合わせて確認してください。

プランメール送信上限(1日)料金
個人向けアカウント100通無料
Google Workspace Business Starter1,500通月額 ¥690 / ユーザー
Google Workspace Business Plus1,500通月額 ¥1,380 / ユーザー

給食弁当の発注メールやキャンセル待ち通知が少数であれば、無料枠から始められます。Google Workspaceを利用する場合も、上記の月額費用は中小規模の事業者が検討しやすい水準です。料金や上限は変更される場合があるため、契約前に公式情報を確認してください。

GASには、次のような制限もあります。

Q2. 複数の仕入れ先に分けて送信するには?

仕入れ先ごとに商品を分ける場合は、商品名と送信先の対応表をコードで管理します。

const supplierConfig = {
  'supplier1@example.com': ['日替わり弁当', 'のり弁当'],
  'supplier2@example.com': ['カツ弁当', '唐揚げ弁当']
};

別の方法として、仕入れ先ごとに集計シートを分ける方法もあります。

方法メリットデメリット
商品名で対応付け設定を一覧で管理できる商品変更時に修正が必要
集計シートを分ける画面上で確認しやすいシート管理が増える

編集部では、商品数が少ない場合は商品名での対応付けを推奨します。

Q3. キャンセル待ちの自動通知を止めたい場合は?

一時停止には、次の方法があります。

方法1: トリガーを削除する

  1. GASエディタのトリガー画面を開く
  2. 対象トリガーのメニューを開く
  3. 「トリガーを削除」を選択する

方法2: 設定シートで制御する

function isWaitlistNotificationEnabled() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const configSheet = ss.getSheetByName('設定');
  return configSheet.getRange(1, 2).getValue() === 'ON';
}

通知関数の冒頭で、この関数を呼び出して判定します。

Q4. GASのコードがエラーになった場合、どうすればよい?

次の手順で確認します。

  1. GASエディタからテスト実行する
  2. 実行履歴でエラー行を確認する
  3. Logger.log()の内容を確認する
  4. シート名、列番号、メールアドレスを見直す
よくあるエラー原因対処法
Cannot read property 'getRange' of nullシート名が違うシート名を確認する
Exception: Invalid emailメール形式が違う送信先を確認する
Service invoked too many times実行回数の上限実行間隔を調整する

Q5. スマートフォンからでも注文を受け付けられる?

Googleフォームは、スマートフォンから回答できます。

Q6. 注文データのバックアップはどうすればよい?

スプレッドシートはGoogleドライブに保存されます。誤削除や設定変更に備え、定期的にコピーを保存してください。

バックアップ方法頻度手間
スプレッドシートをコピー週次数クリック
バージョン履歴を確認必要時少ない
CSVで書き出す月次数分

Q7. 従業員がGASを操作できない場合でも大丈夫?

コードを直接操作しなくても、構築後は注文集計やメール送信を自動化できます。従業員が行う作業は、次のとおりです。

作業頻度担当者
フォームURLを顧客に案内導入時管理者
注文状況を確認随時担当者
キャンセル処理随時管理者

🔗 出典・参考情報

本記事で紹介した設定方法は、次の公式ドキュメントを参照してください。


📝 まとめ

給食弁当業の注文管理は、GASを使うと段階的に自動化できます。最初からすべてを任せるのではなく、集計、発注メール、キャンセル待ちの順に試すと、現場で検証しやすくなります。

自動化で期待できる変化

業務導入前導入後の目安
注文集計1日30〜60分確認中心
発注連絡1日10〜15分内容確認中心
キャンセル待ち管理1日15〜30分状況確認中心
集計ミス手作業に依存入力とコードの確認が重要

削減できる時間は、注文数や運用方法で変わります。導入後も、送信ログと集計結果を確認してください。

導入のステップ

  1. Googleフォームとスプレッドシートを準備(約30分)
  2. GASコードを実装(約60分)
  3. テスト環境で動作確認(約30分)
  4. 本番トリガーを設定
  5. 送信ログを定期的に確認

編集長の最終見解: 自動化の目的は、人員を減らすことではありません。注文確認や顧客対応など、人が判断すべき仕事に時間を戻すことです。GASは、給食弁当業のような小規模事業者が、低コストで業務改善を始める選択肢になります。まずは集計だけを自動化し、確認しながら範囲を広げてください。


Mira / AI経営ラボ 編集長