回答編集履歴

5

2023/09/02 12:54

投稿

退会済みユーザー
test CHANGED
@@ -1,8 +1,8 @@
1
- 質問文のエラーについては
1
+ 質問文のエラーについては、updateDatesSheetの中括弧の位置 がおかしいことが原因です。
2
- updateDatesSheet中括弧の位置 がおかしくなっており、updateDatesSheet関数の続きのif文をupdateDatesSheet関数に含めるとともに
2
+ エラー自体は、updateDatesSheet関数の続きのif文をupdateDatesSheet関数に含めるとともに
3
3
  修正後のupdateDatesSheet関数をform関数の外に出すことで解消されます。
4
4
 
5
- しかし後もエラーが出たということなので、下記に原因と対応を記載します。
5
+ しかし他にも大量バグが残っていてエラーが出、下記に原因と対応を記載します。
6
6
 
7
7
  (注意:以下は、「2023/09/02 14:01のコメント内で共有されたスプレッドシート」の中に記載された、その時点でのコードに対する言及です。以降にコードが編集されていても関知しません。(関知できません))
8
8
 

4

冒頭追記

2023/09/02 09:37

投稿

退会済みユーザー
test CHANGED
@@ -1,3 +1,8 @@
1
+ 質問文のエラーについては
2
+ updateDatesSheetの中括弧の位置 がおかしくなっており、updateDatesSheet関数の続きのif文をupdateDatesSheet関数に含めるとともに
3
+ 修正後のupdateDatesSheet関数をform関数の外に出すことで解消されます。
4
+
5
+ しかしその後もエラーが出たということなので、下記に原因と対応を記載します。
1
6
 
2
7
  (注意:以下は、「2023/09/02 14:01のコメント内で共有されたスプレッドシート」の中に記載された、その時点でのコードに対する言及です。以降にコードが編集されていても関知しません。(関知できません))
3
8
 

3

修正

2023/09/02 07:52

投稿

退会済みユーザー
test CHANGED
@@ -4,7 +4,7 @@
4
4
  ##### 1.「var id = sht.getRange(row, 1).getValue(); //ここのid部分が反応しなくなってしまった。」の原因
5
5
  → スコープ内で、変数idがどこからも参照されていないからです。
6
6
  変数id は、sendEmail関数内で使われているため、sendEmail関数を呼ぶときに、idも一緒に引数として渡してやればよいです。
7
-  
7
+ (idだけでなく、 name, childも sendEmail関数内で使われているため、idと一緒に引数として渡してやる必要があります)
8
8
   
9
9
 
10
10
  ##### 2.「TypeError: Cannot read properties of undefined (reading 'getItemResponses') at form(コード:44:28)」 の原因
@@ -150,8 +150,8 @@
150
150
  updateForm(); // フォームの「空き状況」を更新
151
151
  }
152
152
 
153
- // 追加。メール送信時にidを渡す。
153
+ // 追加。メール送信時にid, name, childを渡す。
154
- sendEmail(mail, date, result, id);
154
+ sendEmail(mail, date, result, id, name, child);
155
155
  }
156
156
 
157
157
  /**
@@ -193,7 +193,7 @@
193
193
 
194
194
 
195
195
  //function sendEmail(mail, preferredDate, result) {
196
- function sendEmail(mail, preferredDate, result, id) { // idを受け取るように修正
196
+ function sendEmail(mail, preferredDate, result, id, name, child) { // id,name,childを受け取るように修正
197
197
  const mailTitle = "予約結果";
198
198
  const imageurl = 'https://chart.apis.google.com/chart?chs=250x250&cht=qr&chl=' + id;
199
199
  const response = UrlFetchApp.fetch(imageurl); // option削除

2

追記

2023/09/02 07:35

投稿

退会済みユーザー
test CHANGED
@@ -1,10 +1,89 @@
1
+
2
+ (注意:以下は、「2023/09/02 14:01のコメント内で共有されたスプレッドシート」の中に記載された、その時点でのコードに対する言及です。以降にコードが編集されていても関知しません。(関知できません))
3
+
4
+ ##### 1.「var id = sht.getRange(row, 1).getValue(); //ここのid部分が反応しなくなってしまった。」の原因
5
+ → スコープ内で、変数idがどこからも参照されていないからです。
6
+ 変数id は、sendEmail関数内で使われているため、sendEmail関数を呼ぶときに、idも一緒に引数として渡してやればよいです。
7
+  
8
+  
9
+
10
+ ##### 2.「TypeError: Cannot read properties of undefined (reading 'getItemResponses') at form(コード:44:28)」 の原因
11
+ → フォーム入力内容を取得する書き方として、getItemResponses関数は、フォームのコンテナバインドスクリプトとして書いたときだけ有効です。
12
+
13
+ 質問者さんによれば、スプレッドシートのコンテナバインドスクリプトとして書かれているとのことですので、getItemResponsesは使えません。
14
+ 代わりに、form関数の冒頭の「var values = e.values」のように、valuesプロパティを使いましょう。
15
+
16
+ ただ、reserveDateに格納しようとしているのは、フォームで入力された予約日ですが、予約日は、form関数の最初の方の
17
+ ```
18
+ var date = values[2];//日付
19
+ ```
20
+ ですでにdate変数として取得済みです。したがって、改めて
21
+ ```
22
+ var reserveDate = values[2];
23
+ ```
24
+ とする必要はありません。date変数をそのまま使いまわせばいいです。
25
+  
26
+  
27
+
28
+ ###### その他
29
+ ##### 3:reserveSheetの未定義エラー
30
+ reserveSheet がどこにも定義されていないため、このままだとエラーになります。
31
+
32
+ ##### 4:予約数更新処理のバグ
33
+ 日程シートの予約数を更新する下記の部分
34
+ ```
35
+ datesSheet.getRange(target.rowNum, 3)
36
+ ```
37
+ ですが、入力範囲を取得しているだけで、値が書き込まれていません。
38
+ 値を書き込むには、「setValue(<値>)」を追加する必要があります。
39
+
40
+ ##### 5. 日付が見つからなかった時のエラー処理
41
+ フォームの回答で日付を選択していますが、万が一、選択肢の日付がスプレッドシート上になかったり、フォームの質問とスプレッドシートのデータの間でコピぺミス等で文字不一致になっている場合、現状のコードだと updateDatesSheet の
42
+ ```
43
+ const index = table.findIndex(row => row[0] === reserveDate);
44
+ ```
45
+ で indexが-1になり、後続の処理でエラーになります。
46
+ したがって、きちんとエラートラップを置くべきです。
1
- {}位置がおかしいです。
47
+ 具体的には、上記行の下に
48
+ ```
49
+ if (index === -1) return "error";
50
+ ```
51
+ を追加します。
52
+
53
+ ##### 6. 定員超過判定のバグ
2
- updateDatesSheet関数form関数中に入っいて、
54
+ 現状、updateDatesSheet関数の「 定員超過しなければ「予約済」に加算する」の中で定員超過判定処理とし
3
- その後ろの
55
+ ```
4
- if (target.reserved < target.cap) {
56
+ if (target.reserved < target.cap) {
57
+ ```
58
+ としていますが、これだと、更新前の予約人数と定員を比べていることになるため、常にtrueになり、実際は超過する場合でも予約できてしまいます。
59
+ ここは、[更新前予約人数+フォームで回答された予約人数]と定員とを比較すべきです。
60
+ このためには、呼び出し元のform関数でupdateDatesSheet関数を呼び出す際、updateDatesSheet関数に、フォームから回答された予約人数の情報を渡してやる必要があります。
61
+
62
+ ##### 7. form.getPublishedUrl()がエラーになる。
63
+ sendEmail関数の中で、
64
+ ```js
65
+ const mailBody = (result === "success")
66
+ ? "予約が完了しました。\n 添付されたQRコードを当日の受付でご提示ください \n"
67
+ + ` 【予約日】:${preferredDate}`
68
+ + '【氏 名】' + name + '\n'
69
+ + '【お申込み人数】' + child + '名\n'
70
+ + '【来場者ID】' + id
71
+ : "定員超過のため予約できませんでした。\n" +
72
+ "下記のフォームから再度申請してください\n" +
73
+ form.getPublishedUrl();
74
+ ```
75
+ としていますが
76
+
77
+ 質問中のコードの「form」は関数でありフォームオブジェクトではないため、getPublishedUrl関数を持っていません。
5
- からif文の終わりまでが updateDatesSheet の外にあになってしっているのがエラーの原因です。
78
+ 定員超過時に form.getPublishedUrl() が呼び出されとエラーになます。
6
-
7
- 部分にバグがなければ、下で動くはずです。
79
+ ここはフォームURLを直接る必要があります
80
+
81
+ ---
82
+
83
+ ### 修正後の全体コード
84
+ 上記を踏まえて修正したものが下記です。(一部の要件が不明確のため、期待する動作になっていない部分があるかもしれませんがあしからず。)
85
+ 注意:updateForm関数は、エラー回避のためダミーで作っていますが、実際は具体的な処理に置き換えてください。
86
+
8
87
  ```js
9
88
  function form(e) {//メイン関数
10
89
  var values = e.values;//フォームの回答を取得
@@ -27,6 +106,11 @@
27
106
  var lastcol = sht.getLastColumn(); // 最終列を取得
28
107
  var range = sht.getRange(1, 1, lastrow, lastcol);
29
108
  var values = range.getValues(); // 情報をオンメモリに保持
109
+
110
+ /*来場者シートのデータを全部取得し、1行ずつチェック。
111
+ A列が空欄の場合はランダムな文字列を記入。
112
+ I列にQRコードの数式を設定
113
+ */
30
114
  for (var i = 1; i < lastrow; i++) {
31
115
  data = values[i][0];
32
116
  if (data == "") {
@@ -38,6 +122,7 @@
38
122
  }
39
123
  range.setValues(values); //スプレッドシートに書き戻し
40
124
 
125
+ /*回答の名前と一致する行の1列目をidとして取得する*/
41
126
  for (let row = 1; row <= lastrow; row++) {
42
127
  if (sht.getRange(row, 3).getValue() == name) {
43
128
  var id = sht.getRange(row, 1).getValue();
@@ -48,39 +133,106 @@
48
133
  // 日程シートから該当日のデータを取得
49
134
  // フォームの送信内容を取得
50
135
 
51
- const items = e.response.getItemResponses();
136
+ // const items = e.response.getItemResponses(); // 削除
137
+ // const reserveDate = items[2].getResponse(); // 下のように修正
52
- const reserveDate = items[2].getResponse();
138
+ const reserveDate = date; // dateをそのまま使う
53
139
 
54
140
  // 予約処理
141
+ const reservationCount = parseInt(child) + 1; // 追加 予約人数(連れの数+1 人)
55
- const result = updateDatesSheet(reserveDate);
142
+ //const result = updateDatesSheet(reserveDate); // 下のように修正。
143
+ const result = updateDatesSheet(reserveDate, reservationCount ); // 予約人数も渡す。
144
+
145
+ // 追加:reserveSheet変数の定義
146
+ const reserveSheet = ss.getSheetByName("予約");
147
+
56
148
  if (result === "success") {
57
- reserveSheet.appendRow([email, reserveDate]); // 予約シートに追記
149
+ reserveSheet.appendRow([mail, reserveDate]); // 予約シートに追記
58
- updateForm(); // フォームの「空き状況」を更新
150
+ updateForm(); // フォームの「空き状況」を更新
59
- }
151
+ }
152
+
153
+ // 追加。メール送信時にidを渡す。
154
+ sendEmail(mail, date, result, id);
60
- }
155
+ }
156
+
61
-
157
+ /**
158
+ * 引数に指定した予約日の予約人数が、定員オーバーでないか確認する。
159
+ * オーバーしていなければ、日程シートの現在の予約数に予約人数を加算し、文字列"success"を返す。
160
+ * オーバーしている場合は、文字列"error"を返す。
161
+ * 引数:reserveDate フォームに入力された予約日
162
+ * reservationCount フォームの回答から計算した予約人数
163
+ */
62
- function updateDatesSheet(reserveDate) {
164
+ // function updateDatesSheet(reserveDate) {
165
+ function updateDatesSheet(reserveDate, reservationCount ) { // 修正:予約人数を受け取る。
63
166
  const ss1 = SpreadsheetApp.openById("シートID入れてます");
64
167
  const datesSheet = ss1.getSheetByName("日程");
65
168
  const table = datesSheet.getDataRange().getValues();
66
169
  const index = table.findIndex(row => row[0] === reserveDate);
170
+
171
+ // 追加:フォームで回答された日付がスプレッドシート中になかった場合の処理。
172
+ if (index === -1) return "error";
173
+
67
174
  const target = {
68
175
  rowNum: index + 1,
69
176
  date: table[index][0],
70
- cap: table[index][1],//日程シートB列
177
+ cap: table[index][1],
71
- reserved: table[index][3],//日程シートのD列(人数シートから集計した人数)
178
+ reserved: table[index][3], // 予約済人数:日程シートのD列
72
- }
179
+ }
180
+
73
181
  // 定員超過しなければ「予約済」に加算する
182
+ //if (target.reserved < target.cap) { // 下記のように修正
183
+ // [更新前予約人数+フォームで回答された予約人数]と定員とを比較する。
74
- if (target.reserved < target.cap) {
184
+ if (target.reserved + reservationCount < target.cap) {
75
- datesSheet.getRange(target.rowNum, 3);
185
+ // datesSheet.getRange(target.rowNum, 3); // 下記のように修正
186
+ // 更新後予約済人数を日程シートの予約済(C列?)に書き込む。
187
+ datesSheet.getRange(target.rowNum, 3).setValue(target.reserved + reservationCount);
76
188
  return "success"
77
189
  } else {
78
190
  return "error"
79
191
  }
80
192
  }
81
193
 
194
+
82
- // function sendEmail ~~~以降略
195
+ //function sendEmail(mail, preferredDate, result) {
83
-
196
+ function sendEmail(mail, preferredDate, result, id) { // idを受け取るように修正
197
+ const mailTitle = "予約結果";
198
+ const imageurl = 'https://chart.apis.google.com/chart?chs=250x250&cht=qr&chl=' + id;
199
+ const response = UrlFetchApp.fetch(imageurl); // option削除
200
+ const blob = response.getBlob().getAs(MimeType.JPEG);
201
+
202
+ const mailBody = (result === "success")
203
+ ? "予約が完了しました。\n 添付されたQRコードを当日の受付でご提示ください \n"
204
+ + ` 【予約日】:${preferredDate}`
205
+ + '【氏 名】' + name + '\n'
206
+ + '【お申込み人数】' + child + '名\n'
207
+ + '【来場者ID】' + id
208
+ : "定員超過のため予約できませんでした。\n" +
209
+ "下記のフォームから再度申請してください\n" +
210
+ //form.getPublishedUrl(); //修正。エラーになるのでURLを直接記述する必要あり。
211
+ "フォームのURL";
212
+
213
+ const option = {
214
+ method: "get",
215
+ "attachments": blob,
216
+ 'name': 'イベント',
217
+ }
218
+
219
+ GmailApp.sendEmail(mail, mailTitle, mailBody, option);
220
+ }
221
+
222
+ function getRndStr() {
223
+ var str = "abcdefghijklmnopqrstuvwxyz0123456789";
224
+ var len = 8;
225
+ var result = "";
226
+ for (var i = 0; i < len; i++) {
227
+ result += str.charAt(Math.floor(Math.random() * str.length));
228
+ }
229
+ return result;
230
+ }
231
+
232
+
233
+ function updateForm() {
234
+ console.log("ダミーのupdateForm()が呼ばれました。")
235
+ }
84
- ```
236
+ ```
85
-
86
-
237
+
238
+

1

修正

2023/09/02 00:50

投稿

退会済みユーザー
test CHANGED
@@ -5,8 +5,7 @@
5
5
  からif文の終わりまでが updateDatesSheet の外にある形になってしまっているのがエラーの原因です。
6
6
 
7
7
  他の部分にバグがなければ、下記で動くはずです。
8
- ```
8
+ ```js
9
-
10
9
  function form(e) {//メイン関数
11
10
  var values = e.values;//フォームの回答を取得
12
11
  //var stamp = values[0];//タイムスタンプを取得
@@ -71,8 +70,6 @@
71
70
  cap: table[index][1],//日程シートB列
72
71
  reserved: table[index][3],//日程シートのD列(人数シートから集計した人数)
73
72
  }
74
-
75
-
76
73
  // 定員超過しなければ「予約済」に加算する
77
74
  if (target.reserved < target.cap) {
78
75
  datesSheet.getRange(target.rowNum, 3);
@@ -82,40 +79,7 @@
82
79
  }
83
80
  }
84
81
 
85
- function sendEmail(mail, preferredDate, result) {
86
-
87
- const mailTitle = "予約結果";
88
- const imageurl = 'https://chart.apis.google.com/chart?chs=250x250&cht=qr&chl=' + id;
89
- const response = UrlFetchApp.fetch(imageurl, option);
90
- const blob = response.getBlob().getAs(MimeType.JPEG);
91
-
92
- const mailBody = (result === "success")
93
- ? "予約が完了しました。\n 添付されたQRコードを当日の受付でご提示ください \n"
94
- + ` 【予約日】:${preferredDate}`
95
- + '【氏 名】' + name + '\n'
82
+ // function sendEmail ~~~以降略
96
- + '【お申込み人数】' + child + '名\n'
97
- + '【来場者ID】' + id
98
- : "定員超過のため予約できませんでした。\n" +
99
- "下記のフォームから再度申請してください\n" +
100
- form.getPublishedUrl();
101
- const option = {
102
- method: "get",
103
- "attachments": blob,
104
- 'name': 'イベント',
105
- }
106
- GmailApp.sendEmail(mail, mailTitle, mailBody, option);
107
-
108
- }
109
-
110
- function getRndStr() {
111
- var str = "abcdefghijklmnopqrstuvwxyz0123456789";
112
- var len = 8;
113
- var result = "";
114
- for (var i = 0; i < len; i++) {
115
- result += str.charAt(Math.floor(Math.random() * str.length));
116
- }
117
- return result;
118
- }
119
83
 
120
84
  ```
121
85