回答編集履歴
8
answer
CHANGED
@@ -82,7 +82,7 @@
|
|
82
82
|
・下記コードは、フォームの回答を集約するスプレッドシートのスクリプトに記述します。
|
83
83
|
・あらかじめトリガーで「フォーム送信時」に「onSubmitForm」関数を実行するように指定しておきます。
|
84
84
|
|
85
|
-
・**あらかめエディタの左の方にある「+サービス」からDrive
|
85
|
+
・**あらかめエディタの左の方にある「+サービス」からDrive APIを追加しておいてください。**
|
86
86
|

|
87
87
|
|
88
88
|
・申請用エクセルから読み取った内容は、フォームの回答を集約するスプレッドシートとは別のシート(説明の便宜上「チェックシート」という名称とします)に記録するようにしています。
|
7
修正:Driveサービス追加の件&Logger内の変数
answer
CHANGED
@@ -81,6 +81,10 @@
|
|
81
81
|
一例として、3.の「フォームからアップロードされた申請用エクセルの内容を読み取って、1行ずつチェックボックスと一緒に記録する」コードを記します。
|
82
82
|
・下記コードは、フォームの回答を集約するスプレッドシートのスクリプトに記述します。
|
83
83
|
・あらかじめトリガーで「フォーム送信時」に「onSubmitForm」関数を実行するように指定しておきます。
|
84
|
+
|
85
|
+
・**あらかめエディタの左の方にある「+サービス」からDriveサービスを追加しておいてください。**
|
86
|
+

|
87
|
+
|
84
88
|
・申請用エクセルから読み取った内容は、フォームの回答を集約するスプレッドシートとは別のシート(説明の便宜上「チェックシート」という名称とします)に記録するようにしています。
|
85
89
|
・質問者さんが処理内容を理解してカスタマイズしやすいように、あえてmap等は使わず冗長なコードにしている部分があります。
|
86
90
|
たとえばコード中で申請エクセルの項目と集計シートの項目の対応を分かりやすくするために、insertValues()の戻り値は配列ではなく、Mapかオブジェクトとして返すようにするなど工夫できるかもしれませんが、ここでは割愛します。
|
@@ -104,7 +108,7 @@
|
|
104
108
|
|
105
109
|
if (file == null) {
|
106
110
|
Logger.log('エクセルファイルを変換できませんでした。\n' +
|
107
|
-
`
|
111
|
+
`fileId:${uploadFileId}`
|
108
112
|
)
|
109
113
|
}
|
110
114
|
const expenseValues = getExpenseValues(file);
|
6
チェックボックスの引数修正
answer
CHANGED
@@ -175,7 +175,7 @@
|
|
175
175
|
checkSheet.appendRow(['=ROW()-1', '', ...values])
|
176
176
|
const lastRow = checkSheet.getLastRow();
|
177
177
|
// チェックボックスをB列に追加
|
178
|
-
checkSheet.getRange(lastRow, 2).insertCheckboxes(
|
178
|
+
checkSheet.getRange(lastRow, 2).insertCheckboxes();
|
179
179
|
}
|
180
180
|
```
|
181
181
|
|
5
answer
CHANGED
@@ -80,7 +80,7 @@
|
|
80
80
|
ユースケースの説明ありがとうございます。
|
81
81
|
一例として、3.の「フォームからアップロードされた申請用エクセルの内容を読み取って、1行ずつチェックボックスと一緒に記録する」コードを記します。
|
82
82
|
・下記コードは、フォームの回答を集約するスプレッドシートのスクリプトに記述します。
|
83
|
-
・あらかじめトリガーで「フォーム送信時」に「
|
83
|
+
・あらかじめトリガーで「フォーム送信時」に「onSubmitForm」関数を実行するように指定しておきます。
|
84
84
|
・申請用エクセルから読み取った内容は、フォームの回答を集約するスプレッドシートとは別のシート(説明の便宜上「チェックシート」という名称とします)に記録するようにしています。
|
85
85
|
・質問者さんが処理内容を理解してカスタマイズしやすいように、あえてmap等は使わず冗長なコードにしている部分があります。
|
86
86
|
たとえばコード中で申請エクセルの項目と集計シートの項目の対応を分かりやすくするために、insertValues()の戻り値は配列ではなく、Mapかオブジェクトとして返すようにするなど工夫できるかもしれませんが、ここでは割愛します。
|
4
answer
CHANGED
@@ -10,8 +10,8 @@
|
|
10
10
|
|
11
11
|
2.申請者は、Eに申請する内容を書き込み、Googleフォーム(F)からアップロードする。
|
12
12
|
|
13
|
-
回答を集計しているGoogleスプレッドシート(S)の
|
13
|
+
3.回答を集計しているGoogleスプレッドシート(S)の
|
14
|
-
|
14
|
+
コンテナバインドスクリプトは下記のような内容とする。(トリガー:フォームの送信時)
|
15
15
|
|
16
16
|
- 回答(アップロード)されたEに対応するGoogleドライブURLを読み取り、
|
17
17
|
- DriveAppサービスを使ってEをGoogleスプレッドシートに変換し、
|
@@ -24,7 +24,7 @@
|
|
24
24
|
・内容が妥当であればリストボックスを承認に変える。
|
25
25
|
・内容に間違いがあれば、リストボックスを否認に変え、「経理担当者連絡欄」列に、申請者に伝えたい内容を記入する。
|
26
26
|
|
27
|
-
5.S2にはボタンがあり、それをクリックすると、以下のような処理を行う(スクリプト)。
|
27
|
+
5.S2にはボタンがあり、それをクリックすると、以下のような処理を行う(S2のスクリプト)。
|
28
28
|
- S2のB列が「承認」の場合は「承認しました」という件名のメールを申請者のメールアドレス宛に送信。
|
29
29
|
- 「否認」の場合は、「差し戻し」の件名で、本文に「経理担当者連絡欄」に入力したメモを記載し、申請者のメールアドレス宛に送信。
|
30
30
|
- 「返信済み」列が空欄の行に関しては、何もしない。
|
@@ -81,11 +81,15 @@
|
|
81
81
|
一例として、3.の「フォームからアップロードされた申請用エクセルの内容を読み取って、1行ずつチェックボックスと一緒に記録する」コードを記します。
|
82
82
|
・下記コードは、フォームの回答を集約するスプレッドシートのスクリプトに記述します。
|
83
83
|
・あらかじめトリガーで「フォーム送信時」に「onSubmit」関数を実行するように指定しておきます。
|
84
|
-
・申請用エクセルから読み取った内容は、フォームの回答を集約するスプレッドシートとは別のシート(「チェックシート」)に記録するようにしています。
|
84
|
+
・申請用エクセルから読み取った内容は、フォームの回答を集約するスプレッドシートとは別のシート(説明の便宜上「チェックシート」という名称とします)に記録するようにしています。
|
85
85
|
・質問者さんが処理内容を理解してカスタマイズしやすいように、あえてmap等は使わず冗長なコードにしている部分があります。
|
86
|
-
たとえばコード中で申請エクセルの項目と集計シートの項目の対応を分かりやすくするために、insertValues()は配列ではなくMapかオブジェクト
|
86
|
+
たとえばコード中で申請エクセルの項目と集計シートの項目の対応を分かりやすくするために、insertValues()の戻り値は配列ではなく、Mapかオブジェクトとして返すようにするなど工夫できるかもしれませんが、ここでは割愛します。
|
87
|
-
・lastRow取得
|
87
|
+
・insertValuesの中のlastRow取得前後など、排他処理を使った方が安全な部分があるかもしれません(ループを使って数秒間に2つのアカウントから10件をほぼ同時書き込みするテストでは特に問題が出ませんでしたが、人数やタイミングによっては問題が生じるかもしれません(未検証))
|
88
88
|
|
89
|
+
・質問者さんが記載している残りのコード(チェックボタン押下時にメール送信、等)は、基本的にチェックシートの方のスクリプトに書く形となります。
|
90
|
+
(少しややこしいですが、下記スクリプトは「フォームの回答を集計しているシート」の方に書きます。
|
91
|
+
一方、「チェックボタンをチェックしたらメール送信する」等のスクリプトは、チェックシートのスクリプトとして書きます)
|
92
|
+
|
89
93
|
```js
|
90
94
|
const CHECKSHEET_ID = 'チェックシートのスプレッドシートID'
|
91
95
|
const SHEET_NAME = 'チェックシートのシート名';
|
3
修正
answer
CHANGED
@@ -182,4 +182,4 @@
|
|
182
182
|

|
183
183
|
|
184
184
|
チェックシート(フォームから2件投稿後の状態)
|
185
|
-

|
2
追加
answer
CHANGED
@@ -73,4 +73,113 @@
|
|
73
73
|
|
74
74
|
質問文に記載の「最終的にスプレッドシート内に申請数単位でに承認ボタンを設置し、承認メールを自動送信させるつもり」との文面から察するに、ある程度お手持ちのコードがあるが、一部やり方が分からなくて詰まっている、という状況ではないでしょうか。
|
75
75
|
|
76
|
-
ならば、そのコードを質問文に記載し、「この部分のこういう機能を実現するためのやり方がわからない」、といった具体的な提示をしていただいた方が、回答も付きやすいのではないかと思います。
|
76
|
+
ならば、そのコードを質問文に記載し、「この部分のこういう機能を実現するためのやり方がわからない」、といった具体的な提示をしていただいた方が、回答も付きやすいのではないかと思います。
|
77
|
+
|
78
|
+
---
|
79
|
+
【9/11追記】
|
80
|
+
ユースケースの説明ありがとうございます。
|
81
|
+
一例として、3.の「フォームからアップロードされた申請用エクセルの内容を読み取って、1行ずつチェックボックスと一緒に記録する」コードを記します。
|
82
|
+
・下記コードは、フォームの回答を集約するスプレッドシートのスクリプトに記述します。
|
83
|
+
・あらかじめトリガーで「フォーム送信時」に「onSubmit」関数を実行するように指定しておきます。
|
84
|
+
・申請用エクセルから読み取った内容は、フォームの回答を集約するスプレッドシートとは別のシート(「チェックシート」)に記録するようにしています。
|
85
|
+
・質問者さんが処理内容を理解してカスタマイズしやすいように、あえてmap等は使わず冗長なコードにしている部分があります。
|
86
|
+
たとえばコード中で申請エクセルの項目と集計シートの項目の対応を分かりやすくするために、insertValues()は配列ではなくMapかオブジェクトで返すようにするなど工夫できるかもしれませんがここでは割愛します。、
|
87
|
+
・lastRow取得のところなど、排他処理を使った方が安全な部分はあるかもしれません(ループを使って数秒間に2つのアカウントから10件をほぼ同時書き込みするテストでは特に問題が出ませんでしたが、人数やタイミングによっては問題が生じるかもしれません(未検証))
|
88
|
+
|
89
|
+
```js
|
90
|
+
const CHECKSHEET_ID = 'チェックシートのスプレッドシートID'
|
91
|
+
const SHEET_NAME = 'チェックシートのシート名';
|
92
|
+
const checkSheet = SpreadsheetApp.openById(CHECKSHEET_ID).getSheetByName(
|
93
|
+
SHEET_NAME);
|
94
|
+
|
95
|
+
function onSubmitForm(e) {
|
96
|
+
for (let i = 0; i <= e.range.rowEnd - e.range.rowStart; i++) {
|
97
|
+
const uploadFileId = e.namedValues['アップロードファイル'][i]
|
98
|
+
.replace('https://drive.google.com/open?id=', '');
|
99
|
+
const file = convertGSpreadFile(uploadFileId);
|
100
|
+
|
101
|
+
if (file == null) {
|
102
|
+
Logger.log('エクセルファイルを変換できませんでした。\n' +
|
103
|
+
`timestamp: ${timestamp}\n mail:${mailAddress}\n fileId:${uploadFileId}`
|
104
|
+
)
|
105
|
+
}
|
106
|
+
const expenseValues = getExpenseValues(file);
|
107
|
+
if (expenseValues == null) {
|
108
|
+
Logger.log('申請書ファイルの内容を読み取れませんでした。');
|
109
|
+
}
|
110
|
+
// 内容を読み取ったら変換後のGoogleスプレッドシートは削除する。
|
111
|
+
Drive.Files.remove(file.getId());
|
112
|
+
insertValues(expenseValues);
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
/***
|
117
|
+
エクセルファイルをGoogleスプレッドシートに変換する。
|
118
|
+
引 数: (String) fileId: 変換対象のエクセルのファイルID(Googleドライブ上のファイルID)
|
119
|
+
戻り値: (File):変換後に生成されたGoogleスプレッドシートのFileオブジェクト
|
120
|
+
(変換に失敗した場合:null)
|
121
|
+
***/
|
122
|
+
function convertGSpreadFile(fileId) {
|
123
|
+
try {
|
124
|
+
const excelFile = DriveApp.getFileById(fileId);
|
125
|
+
const blob = excelFile.getBlob();
|
126
|
+
|
127
|
+
const resource = {
|
128
|
+
title: excelFile.getName().replace(/.xlsx?/, ""),
|
129
|
+
key: fileId
|
130
|
+
};
|
131
|
+
|
132
|
+
return Drive.Files.insert(resource, blob, {
|
133
|
+
convert: true
|
134
|
+
});
|
135
|
+
|
136
|
+
} catch (err) {
|
137
|
+
Logger.log(err.toString());
|
138
|
+
return null;
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
/***
|
143
|
+
ファイルの内容を読み取って配列にして返す
|
144
|
+
引 数: (File) file: 内容を読み取る対象のGoogleスプレッドシートファイル
|
145
|
+
戻り値: (Array):スプレッドシートのB列の内容の配列
|
146
|
+
(読み取りに失敗した場合:null)
|
147
|
+
***/
|
148
|
+
function getExpenseValues(file) {
|
149
|
+
const sh = SpreadsheetApp.openById(file.getId());
|
150
|
+
const vals = sh.getDataRange().getValues();
|
151
|
+
try {
|
152
|
+
const ret = [];
|
153
|
+
for (let i = 0; i < vals.length; i++) {
|
154
|
+
ret.push(vals[i][1]);
|
155
|
+
}
|
156
|
+
return ret;
|
157
|
+
} catch (err) {
|
158
|
+
Logger.log(err.toString())
|
159
|
+
Logger.log(`ファイル内容:${vals}`)
|
160
|
+
return null;
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
/***
|
165
|
+
チェックシートにデータを挿入する。
|
166
|
+
引 数: (Array) values: エクセルから読み取ったデータの配列
|
167
|
+
戻り値: なし
|
168
|
+
***/
|
169
|
+
function insertValues(values) {
|
170
|
+
Logger.log(values)
|
171
|
+
checkSheet.appendRow(['=ROW()-1', '', ...values])
|
172
|
+
const lastRow = checkSheet.getLastRow();
|
173
|
+
// チェックボックスをB列に追加
|
174
|
+
checkSheet.getRange(lastRow, 2).insertCheckboxes(false);
|
175
|
+
}
|
176
|
+
```
|
177
|
+
|
178
|
+
フォーム
|
179
|
+

|
180
|
+
|
181
|
+
申請用エクセル
|
182
|
+

|
183
|
+
|
184
|
+
チェックシート(フォームから2件投稿後の状態)
|
185
|
+

|
1
修正
answer
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
以下のようなごく単純な交
|
1
|
+
以下のようなごく単純な交通費申請のワークフローを考えてみましょう。
|
2
2
|
|
3
|
-
・申請内容は、1つ(「交費精算の承認」)
|
3
|
+
・申請内容は、1つ(「交通費精算の承認」)
|
4
4
|
・承認者は、1人(経理担当者Aさん)
|
5
5
|
|
6
6
|
|