全国オンライン対応受付 平日 9:00-18:00
お問い合わせ

開発記録 / Fuhne制作記 / Vol.16 Fuhne制作記 Vol.1

記事 02

注文受付期間と枠上限の実装——時間と件数で注文を制御する

Instagramで告知を読む、ということも一つだ。しかしそれはお客さんが自分で確認しなければならない。システムならば、確認するまでもなく「今は注文できません」と表示できる。焼き菓子店のシステムが実現すべき最も重要なことがここにあった。

2026-06-07 公開

「今週はもう注文できませんよね」

お客さんがそれを知る方法は何だろうか。

Instagramで告知を読む、ということも一つだ。しかしそれはお客さんが自分で確認しなければならない。システムならば、確認するまでもなく「今は注文できません」と表示できる。焼き菓子店のシステムが実現すべき最も重要なことがここにあった。


「いつが受付期間か」を判定する

受付期間は日曜0時〜木曜12時だ。それ以外は受け付けない。

function isAcceptingOrders() {
  const now = new Date();
  const day = now.getDay();    // 0=日, 1=月, ..., 6=土
  const hour = now.getHours();

  if (day === 5) return false; // 金曜は不可
  if (day === 6) return false; // 土曜は不可
  if (day === 4 && hour >= 12) return false; // 木曜12時以降は不可

  return true;
}

この関数がtrueのときだけ注文フォームを表示する。falseのとき、「現在注文は受け付けておりません。受付時間は日曜0時〜木曜12時です」という画面を表示する。お客さんは次の受付開始時刻を見て、また来てくれる。

この判定はGAS側でも同じロジックを持つ。フロントエンドで突破しようとした送信は、GASが拒否する。


時間帯ごとに枠を数える

土曜の受け渡し時間帯は13時・14時・15時・16時の4枠で、各5件まで。これを「在庫」として管理する。

GASが現在の予約状況を返す。

function getSlotCounts() {
  const sheet = ss.getSheetByName('注文データ');
  const rows = sheet.getDataRange().getValues();
  const sat = getThisSaturday();
  const counts = { '13時': 0, '14時': 0, '15時': 0, '16時': 0 };

  rows.slice(1).forEach(r => {
    const receiveDate = new Date(r[4]);
    receiveDate.setHours(0, 0, 0, 0);
    const slot = r[5];
    const status = r[10];

    if (receiveDate.getTime() === sat.getTime() &&
        status !== 'キャンセル' &&
        counts.hasOwnProperty(slot)) {
      counts[slot]++;
    }
  });

  return counts;
}

今週の土曜に紐づく注文だけをカウントする。キャンセルになったものは除く。この関数の結果をフォームが受け取り、5件に達した時間帯はグレーアウトして選択不可にする。


「今週の土曜」を計算する

getThisSaturday()関数は今週の土曜日の日付を返す。

function getThisSaturday() {
  const now = new Date();
  const day = now.getDay();
  const diff = day === 6 ? 0 : 6 - day;
  const sat = new Date(now);
  sat.setDate(sat.getDate() + diff);
  sat.setHours(0, 0, 0, 0);
  return sat;
}

day === 6のとき(土曜日)はdiffが0で今日が返る。それ以外は次の土曜までの日数を計算する。このシンプルな関数が「今週の注文」の基準点になっている。


注文確定時の同時実行問題

2人が同じ時間帯の最後の1枠を同時に選んで送信した場合、両方に「予約できました」と返してしまう可能性がある。

GASのLockServiceで排他制御を行う。ロックを取った処理だけがスプレッドシートに書き込む。ロックを取れなかった処理は「他の方の注文で満枠になりました」という結果を返す。

入退室管理システム・予約システムと全く同じパターンだ。「複数人が同時に動かす可能性がある在庫」を扱うとき、排他制御は必ず必要になる。


タイムゾーンの罠

受付期間の判定で一つ注意が必要だった。GASのnew Date()はGASプロジェクトのタイムゾーン設定に依存する。デフォルトがUTCのプロジェクトでは、日本時間の木曜12時が「木曜3時(UTC)」として計算される。

GASプロジェクトの設定でタイムゾーンを「Asia/Tokyo」に変更した。日付の比較にUtilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd')を使う形に統一した。

「なぜ木曜の昼に注文できなかったのか」という問い合わせが来る前に、確認できてよかった。


*次回は「管理画面に商品写真登録機能を追加した話——GASのDriveスコープとbase64アップロード」*

*シンプルシステム株式会社 代表 伊藤勝彦*