0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GAS】Googleフォーム×在庫管理!日次運用② 注文履歴へデータを退避して残数をリセットする

0
Last updated at Posted at 2026-07-23

今までの記事一覧
Googleフォーム×GASで実現する業務自動化シリーズ全記事まとめ目次

前提

この記事は、フォーム回答を保存しているスプレッドシート側のGASを前提にしています。

トリガーは以下を設定してください。

  • フォーム送信時に実行する関数:onFormSubmit
  • イベントのソース:スプレッドシートから
  • イベントの種類:フォーム送信時

スプレッドシート構成

スプレッドシート「集計シート」をこの図のように設定しています。

image
  • A1:D6 セル:商品マスタ(商品コードや現在の残数が入っている)
  • 11行目以下:フォームから送信された注文の受付内容が記録される
  • 図の赤字の内容の数式が入っている
    ※以前作ったこの記事の数式をそのまま生かしています。ただし、変更フォームによって在庫不足による注文数の修正が発生したときのために、有効注文数の数式を少しだけ変更し =IF(ISNUMBER(修正数のセル), 修正数のセル, 注文数のセル) としておきます。こうすることで、『修正数』の欄に修正後の確定数を書き込むだけで、有効注文数も、商品マスタの残数も、シート側で全自動で連動して計算されるようになります。

おさらい

前回は、GASを使ってGoogleフォームの受付を停止したり再開したりする処理を作りました。
あとはトリガーで動かすだけ.....でもその前に.....

毎朝の受付を開始する前に、前日の注文データをどう扱うか考える必要があります。
集計シートをそのまま使い続けると、前日のデータが残ってしまいます。
そこで、1日の終わりに注文履歴シートへ退避し、集計シートをクリアする運用にしたいと思います。

今回のミッション

  • スプレッドシート上にあらかじめ「注文履歴」シートを作成しておく。
    1行目の項目は「集計シート」のデータをそのままコピペできるよう、このような項目にしておくといいでしょう。

A1. 日時
B1. メールアドレス
C1. 氏名
D1. 注文数_ハンバーグ弁当
E1. 修正数_ハンバーグ弁当
F1. 有効注文数_ハンバーグ弁当



M1. 変更フォームの事前入力URL

「注文数_商品名」「修正数_商品名」「有効注文数_商品名」にしておくと後で集計やピボットテーブルを作成するときに便利です。

  • フォームからの注文を受け付ける「集計シート」の注文データを「注文履歴」シートに追加する。
  • 「集計シート」のデータ部分(11行目以降)をクリアする。

※「集計シート」のデータをクリアすることで、シート上の関数によって自動的に残数がリセットされます。
※「集計シート」だとネーミングがややこしいので「日次注文」などに名前を変えてもいいかもしれません。その場合はGASコードでもこのように変えてください。

 const sheet_summary = ss.getSheetByName("日次注文");//"集計シート"から変更

この記事ではこのまま「集計シート」とします。

今回のキモはコレ!

データ範囲を変数化

「集計シート」の11行目以降にフォームからのデータが入るので、11行目から最終行までの範囲を変数 dataRange に格納します。データ範囲を変数化しておくことで、「データの取得」と「データのクリア」の両方で使い回せるため便利です。

  • データ取得時(11行目から取得するため、行数は 最終行 - 10 となります)
  if (summaryLastRow >= 11) {
    const summaryLastCol = sheet_summary.getLastColumn();
    //11行目から最終行(行数は summaryLastRow - 10)
    const dataRange = sheet_summary.getRange(11, 1, summaryLastRow - 10, summaryLastCol);
    const data = dataRange.getValues();
  • データクリア時
dataRange.clearContent();

サブ関数 updateFormOptions() を活用

以前の記事で作ったサブ関数 updateFormOptions() をそのまま使います。
このサブ関数は、シートの商品マスタから残数を抽出してフォームを更新するものです。シート上のデータをクリアすると、数式によってシート上の残数がリセットされます。その状態で updateFormOptions() を実行することで、自動的にフォーム上の選択肢・残数も初期状態へとリセットされる仕組みです。また、このサブ関数内では残数に応じてフォームの受付停止・再開も自動で行っています。

※このように汎用的なサブ関数を作っておくと、コードの重複を減らせるだけでなく、修正が必要になった場合も1か所を直すだけで済みます。

GASコード

メイン関数

//★グローバルスコープ
const form = FormApp.openById("1******"); // 注文フォームの編集用IDを入れる
const corForm = FormApp.openById("1######"); // 変更フォームの編集用IDを入れる

function summaryCopy() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();

  // 1. 集計シートの注文データを注文履歴シートにコピー

  //集計シートの最終行と最終列取得し、注文内容を変数dataに入れる
  const sheet_summary = ss.getSheetByName("集計シート");
  const summaryLastRow = sheet_summary
    .getRange(sheet_summary.getMaxRows(), 1)
    .getNextDataCell(SpreadsheetApp.Direction.UP)
    .getRow();

  //11行目以降に注文データがある場合(注文がある場合)
  if (summaryLastRow >= 11) {
    const summaryLastCol = sheet_summary.getLastColumn();
    const dataRange = sheet_summary.getRange(11, 1, summaryLastRow - 10, summaryLastCol);
    const data = dataRange.getValues();

    //注文履歴シートの最終行以降に変数dataの内容を入れる
    const sheet_history = ss.getSheetByName("注文履歴");
    const historyLastRow = sheet_history.getLastRow();
    sheet_history.getRange(historyLastRow + 1, 1, data.length, data[0].length).setValues(data);

    // 2. 集計シートの注文データを消去する
    dataRange.clearContent();
  }

  // 3. フォームの残数表示・受付状態をリセット
  //以前作った【サブ関数】(引数を省略すると、自動で itemMaster を取得するように作ってある)
  updateFormOptions();

  // 4. 締め切りトリガーをセット
     //次回以降実装予定 
}

サブ関数

function updateFormOptions(itemMaster) {

  //手動更新等で itemMaster が渡されない場合はここで取得
  if (!itemMaster) {
    const sheet_summary = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("集計シート");

    //シートから手動で更新した場合(スマホからも含む)は、念のためスプレッドシートを強制再計算させる
    SpreadsheetApp.flush();

    // B1から右方向のデータ終端(列数取得用)
    const summaryLastCol = sheet_summary.getRange("B1").getNextDataCell(SpreadsheetApp.Direction.NEXT).getColumn();

    // 上部で宣言された引数の変数(itemMaster)にそのままデータを代入する
    itemMaster = sheet_summary.getRange(1, 1, 6, summaryLastCol).getValues();
  }

  // マスタの列数(B列〜最終列)を取得
  const summaryLastCol = itemMaster[0].length;
  const formDescription = ["【現在の残数状況】"];
  let sumStockNum = 0;    //商品全部の残数を足したもの

  // 2. 商品ごとにループ処理(B列=インデックス1 から開始)
  for (let col = 1; col < summaryLastCol; col++) {
    const productName = itemMaster[0][col]; // 1行目:商品名
    const questionId = itemMaster[2][col]; // 3行目:フォームの質問ID
    const stockNum = Number(itemMaster[5][col]); // 6行目:最新の残数

    // 質問IDが空欄の場合はスキップ(エラー防止)
    if (!questionId) continue;

    try {
      sumStockNum += stockNum;  //商品全部の残数を足していく
      // 3. 質問IDを元に、フォームから対象のプルダウン(ListItem)を取得
      const listItem = form.getItemById(questionId).asListItem();

      // 4. 残数に応じた選択肢(choices)を動的に組み立てる
      const choices = []; //フォームの選択肢を入れる配列

      if (stockNum <= 0) {
        // 在庫がない場合は「0」にする(万が一マイナスになっても表示は0)
        choices.push("0");
      } else {
        // 在庫がある場合は 1 〜 残数 までの数字を選択肢にする
        // (0個も選択肢に入れたい場合は i = 0 からスタート)
        for (let i = 1; i <= stockNum; i++) {
          choices.push(String(i));
        }
      }

      // 5. フォームのプルダウン選択肢を更新 
      listItem.setChoiceValues(choices);

      // 質問のタイトルやヘルプテキスト(説明欄)も更新したい場合はここで変更可能
      listItem.setHelpText(`残りあと ${stockNum} 個です`);

      // 6. フォームタイトル下の説明欄を更新
      formDescription.push(productName + ":" + stockNum);


    } catch (e) {
      Logger.log(`質問ID [${questionId}] の更新中にエラーが発生しました: ${e.message}`);
    }
  }
  // フォームタイトル下の説明欄を書き換え
  const formDescriptionText = formDescription.join("\n");
  form.setDescription(formDescriptionText);   //注文フォーム
  corForm.setDescription(formDescriptionText + "\n ※元々のご自身の注文数にこの数を足したものが、注文可能数です。");  //変更フォーム

  if (sumStockNum === 0) {    //もし商品全部の残数(sumStockNum)が0だったらフォーム受付停止
    if (form.isAcceptingResponses() === true) {  // フォームがまだ受け付けていたら
      form.setCustomClosedFormMessage("本日の注文受付は【完売】のため終了いたしました。またのご利用をお待ちしております!");
      form.setAcceptingResponses(false); // 新規受付を停止
    }
  } else {
    //フォームが受付停止になっていたら再開
    if (form.isAcceptingResponses() === false) {
      form.setAcceptingResponses(true);
    }
    //【サブ関数】売り切れ商品を売り切れセクションに移動
    moveSoldoutItem(itemMaster)
  }

  return (formDescriptionText);
}

動作確認

それでは実行してみましょう。
この状態のスプレッドシートから開始します。注文は3件入っています。残数はすべて0になっているため、フォームは受付停止している状態です。

image image

実行すると、集計シートの11行目以下がクリアされ、残数は初期値(10個)に戻っています。

image

こちらは「注文履歴」シートです。2行目以下にデータが転記されています。

image

フォームは受付再開されています。残数もリセットされています。

image

まとめ

今回は、日次集計用の「集計シート」をリセットし、「注文履歴」シートにデータを蓄積すると同時に、フォームの残数も自動でリセットする処理を作りました。
「注文履歴」シートへデータを蓄積することで、月次の集計や、ピボットテーブルを使った商品別・利用者別の集計などもしやすくなりました。
あとはこの処理をトリガーで毎日自動実行できるように設定すれば完成です。
次回はトリガーもGASで自動設定する方法を解説していきたいと思います。

今回の成果コードは、GASコード を参照してください。


次回の記事はこちら
Googleフォーム×在庫管理!日次運用③特定日時に発動するトリガーを毎日自動作成する


image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?