質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

Q&A

解決済

1回答

9085閲覧

(GAS)メール本文に記載したURLリンクの押下をトリガにしてスプレッドシートに値を入力したい。

退会済みユーザー

退会済みユーザー

総合スコア0

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

0グッド

1クリップ

投稿2018/09/13 06:09

編集2018/10/17 04:50

前提・実現したいこと

Google Apps Scriptで物品の購入申請、承認フローを作成したいと考えております。
(以下のようなフローです)

1.物品を購入したい人がフォームで申請(物品の種類、数量、金額、など)
2.フォームで申請した内容をスプレッドシートに自動で記載。承認者に申請内容を自動でメール。
3.承認者へのメール内容は、本文に申請内容(物品の種類、数量、金額、など)を記載し、「承認」「否認」のURLリンクも記載する。
4.承認者が「承認」若しくは「否認」のURLリンクを押すと、『承認しました』若しくは『否認しました』と記載したHTMLを表示。更にこのタイミングで、該当の申請に対し、スプレッドシート上の新たな列に【承認】or【否認】と入力したい。


【更新】
回答でご指摘頂いた内容について本文にも追記します。
・書き込むスプレッドシートはidで特定して、その中のシート『フォームの回答』に書き込みを行う。
・『フォームの回答』シートには、フォームから申請された情報が入力されている。
タイトル行(A1~I1)には以下のタイトルが記入済み(タイムスタンプ、メールアドレス、氏名、部門、
機材種別、購入希望日、商品名、商品URL、個数)。
2行目以下はフォームからの申請内容が入力されている。

・『承認』の場合はJ列に"〇"を、『否認』の場合はJ列に"×"を入力したい。
(タイムスタンプが一致する行に対して。)

【再更新】
フォームの入力内容を追加する必要が出たので、
『承認』『否認』の結果入力をJ列ではなく、N列(14列目)に変更したいです。
N列に"〇"、"×"を入力したい。

発生している問題・エラーメッセージ

実現したいことの4.の途中までは出来ました。
『更にこのタイミングで、該当の申請に対し、スプレッドシート上の新たな列に【承認】or【否認】と入力したい。』の部分が出来ていません。

メール本文に記載したURLリンクの押下をトリガにしてスプレッドシートに値を入力する事は出来るのでしょうか。
フォームから申請すると、スプレッドシート上にタイムスタンプが自動で入力されるので、
タイムスタンプを検索して、該当の申請に対して【承認】【否認】を入力したいと思っています。

該当のソースコード

●send_email.gs

function sendHtmlMail(e) {

var answer1 = e.namedValues['購入者 氏名']; //フォーム作成時に設定した項目名
var answer2 = e.namedValues['部門']; //フォーム作成時に設定した項目名
var answer3 = e.namedValues['商品名']; //フォーム作成時に設定した項目名
var answer4 = e.namedValues['数量']; //フォーム作成時に設定した項目名
var answer5 = e.namedValues['単価(税込み)']; //フォーム作成時に設定した項目名
var answer6 = e.namedValues['購入理由']; //フォーム作成時に設定した項目名
var answer7 = e.namedValues['購入先(URL等)']; //フォーム作成時に設定した項目名
var answer8 = e.namedValues['優先度']; //フォーム作成時に設定した項目名

var subject = '備品購入申請のお知らせ'; //件名
var body = 'htmlメールが表示できませんでした'; //本文(表示不可時)

var timeStamp=e.namedValues["タイムスタンプ"];

/* メール本文 */
var html = "備品購入申請がありますので承認をお願い致します。<br><br>";
html += "申請内容<br><br>";

html += "購入者 氏名:" + answer1 + "<br>";
html += "商品名:" + answer3 + "<br>";
html += "数量:" + answer4 + "<br>";
html += "単価(税込み):" + answer5 + "<br>";
html += "購入理由:" + answer6 + "<br>";
html += "購入先(URL等):" + answer7 + "<br>";
html += "優先度:" + answer8 + "<br>";

html += "タイムスタンプ:" + timeStamp + "<br>";

html += "承認しますか?<br><br>";

/* 承認・否認 */
html += '<a href="https://script.google.com/*******/exec?p=ok&t='+timeStamp+'">承認</a><br>';
html += '<a href="https://script.google.com/*******/exec?p=ng&t='+timeStamp+'">否認</a><br>';

/* メールを送信 */
if
(answer2 == '1課') {
GmailApp.sendEmail(
'メールアドレス1',
subject,
body,
{
htmlBody: html
}
);
}

else if
(answer2 == '2課') {
GmailApp.sendEmail(
'メールアドレス2',
subject,
body,
{
htmlBody: html
}
);
}

else
{
GmailApp.sendEmail(
'メールアドレス3',
subject,
body,
{
htmlBody: html
}
);
}
}


●ok.html

<!DOCTYPE html> <html> <head> <base target="_top"> </head> <body> <h1>備品購入申請を承認しました</h1> あなたは備品購入申請を承認しました </body> </html>

●ng.html

<!DOCTYPE html> <html> <head> <base target="_top"> </head> <body> <h1>備品購入申請を否認しました</h1> あなたは備品購入申請を承認しませんでした </body> </html>

●Error.html

<!DOCTYPE html> <html> <head> <base target="_top"> </head> <body> URLが正しくありません。ここはエラーページです<br><br> </body> </html>

●doGet.gs

function doGet(e){
var page=e.parameter["p"];
var timeStamp=e.parameter["t"];

if(page == "ok" && timeStamp){
setter(timeStamp, "○");
return HtmlService.createHtmlOutputFromFile('ok');
}
else if(page == "ng" && timeStamp){
setter(timeStamp, "×");
return HtmlService.createHtmlOutputFromFile('ng');
}

else{
return HtmlService.createHtmlOutputFromFile('Error');
}

}
function setter(timestamp, str) {
var sh = SpreadsheetApp.openById("スプレッドシートID").getSheetByName("フォームの回答");
var vals = sh.getDataRange().getValues();
var row = -1;
for(var i = 1; i < vals.length; i++) {
if(Utilities.formatDate(vals[i][0], "JST", "yyyy/MM/dd HH:mm:ss") == timestamp) {
row = i + 1;
}
}
if(row != -1) {
sh.getRange(row, 14, 1, 1).setValue(str);
}
}


試したこと

1.申請フォーム作成済み。
2.フォームの送信をトリガにして承認者へ承認依頼メールを送信→作成済み。
3.承認者へのメール(申請内容、「承認」「否認」のURLリンクも記載)→作成済み。
4.「承認」若しくは「否認」のURLリンクを押すと、『承認しました』若しくは『否認しました』と記載したHTMLを表示。→作成済み。

「承認」若しくは「否認」のURLリンクを押すことで承認したか否認したかを判断して、その内容をスプレッドシートに記入したい(タイムスタンプでどの申請かを判定)と考えておりますが、そのようなことが可能なのか、どのようにすれば良いか分かりません。

当方GASはおろかプログラミング自体が素人のため、ネットで色々調べてソースをコピペしたりしながらなんとか途中まで作成しました。
その為、ソースのちょっとした修正や、キーワードだけでの説明を理解することが難しい為、ご回答頂ける場合は極力ソースコードなども省略せず記載頂けますと幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

doGet.gsで、returnする前に、書き込みをすればよいと思います。

ソースコードですが、書き込むべきスプレッドシートはどうやって特定するのか(スプレッドシートのidなのか、driveのフォルダidとスプレッドシートの名前の組み合わせなのか)や、そのスプレッドシートの何というシートのどこのセルに、何と何を書き込むのかを具体的に仕様として示していただかない限り、有意な回答は得られないと思います。

-- 追記
今のままではタイムスタンプが送信されないので

javascript

1html += '<a href="https://*****/exec?p=ok&t='+timeStamp+'">承認</a><br>'; 2html += '<a href="https://*****/exec?p=ng&t='+timeStamp+'">否認</a><br>';

のようにしてください。するとクリック時にタイムスタンプが送信できます。

その状態で

javascript

1function doGet(e){ 2 var page=e.parameter["p"]; 3 var timeStamp=e.parameter["t"]; 4 5 if(page == "ok" && timeStamp){ 6 setter(timeStamp, "○"); 7 return HtmlService.createHtmlOutputFromFile('ok'); 8 } 9 else if(page == "ng" && timeStamp){ 10 setter(timeStamp, "×"); 11 return HtmlService.createHtmlOutputFromFile('ng'); 12 } 13 14 else{ 15 return HtmlService.createHtmlOutputFromFile('Error'); 16 } 17 18} 19function setter(timestamp, str) { 20 var sh = SpreadsheetApp.openById("").getSheetByName("フォームの回答"); 21 var vals = sh.getDataRange().getValues(); 22 var row = -1; 23 for(var i = 1; i < vals.length; i++) { 24 if(Utilities.formatDate(vals[i][0], "JST", "yyyy/MM/dd HH:mm:ss") == timestamp) { 25 row = i + 1; 26 } 27 } 28 if(row != -1) { 29 sh.getRange(row, 14, 1, 1).setValue(str); 30 } 31} 32

とやると、書き込みができるのではないかと思います。

--- 追記
下記のテスト関数を追加して、関数を実行からテストして書き込まれるか見ていただけますか?

javascript

1function test() { 2var timestamp = "シートにあるタイムスタンプ"; //固定値 3var str = "○"; 4setter(timestamp, str); 5}

投稿2018/09/13 09:25

編集2018/10/15 01:02
papinianus

総合スコア12705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/09/13 12:04

早速ご回答頂きありがとうございます。 ご指摘の内容について、的を得た回答になっているか分かりませんが、以下の様な仕様で考えています。 ----------------------- ・書き込むスプレッドシートはidで特定して、その中のシート『フォームの回答』に書き込みを行う。 ・『フォームの回答』シートには、フォームから申請された情報が入力されている。 タイトル行(A1~I1)には以下のタイトルが記入済み(タイムスタンプ、メールアドレス、氏名、部門、機材種別、購入希望日、商品名、商品URL、個数)。 2行目以下はフォームからの申請内容が入力されている。 ・『承認』の場合はJ列に"〇"を、『否認』の場合はJ列に"×"を入力したい。  (タイムスタンプが一致する行に対して。) -----------------------
退会済みユーザー

退会済みユーザー

2018/09/21 08:10

コードをご教示頂きありがとうございます。 確認してみましたが、承認→〇、否認→×の書き込みがやはり上手く行かないようです。 setterに対して何かトリガーの設定をする必要などがあるのでしょうか? もう少し動作確認を重ねてみます。
papinianus

2018/09/21 08:36

setterに特段トリガはないです。
papinianus

2018/09/21 08:40 編集

すみません。間違ってました。再度追記します。 setterに引数を与えてませんでした。改訂したので、再度ご確認ください
退会済みユーザー

退会済みユーザー

2018/09/25 08:54

テスト関数ですが、こちらを追加して、スクリプトエディタの「関数の実行」からtest関数を実行("シートにあるタイムスタンプ"の部分には既にスプレッドシートに記入されている、いずれかの行のタイムスタンプを記入して)すると言うことで良いでしょうか。 確認して見ましたが該当の行に「〇」は書込み出来ていないようです。 また、新たにご教示頂いたdoGet、setterの関数についても確認して見ましたが、やはり上手く書込み出来ていないようです。setterの中の、 var sh = SpreadsheetApp.openById("").getSheetByName("フォームの回答"); ですが、""の中にはスプレッドシートのIDを記入する認識ですが間違いないでしょうか? 何度もすみませんが宜しくお願い致します。
papinianus

2018/09/25 09:22

何度もテストしていただいたのにすみません。 質問していただいた部分についてのご認識に誤りはありません。 少し処理を見直してみます。
退会済みユーザー

退会済みユーザー

2018/09/26 02:23

ありがとうございます。大変申し訳ありませんが、 フォームの入力内容を追加する必要が出たので、『承認』『否認』の結果入力をJ列ではなく、N列(14列目)に変更したいです。(N列に"〇"、"×"を入力したい)
macaron_xxx

2018/09/27 04:14

横槍ですが、getValues()で取得するタイムスタンプ列は日付型なので、パラメータで渡ってきたタイムスタンプとは一致しないでしょう。 timestampの渡し方を工夫しないといけないですね。
papinianus

2018/09/28 02:18 編集

macaron_xxxさん DateTime型をtoStringしたものどうしになるから(jsの挙動として、アンカでは文字列と+にするときに文字列になり、送信された文字列と比較するときにシートのvalueのほうも文字列になると思った)同じになるかなー的なゆるい発想でした。 ご提示の線で改訂します。 (+0900のところの+がurlから渡ってきたものだと消えてました)
papinianus

2018/09/28 02:16

hkagesbさん 改訂したコードで実際にformを作り、doGetを作ってトライしてN列に書かれたことを検証しています。 doGetやsetterだけでなく、htmlリンクを作るところも変えているのでご対応ください。
退会済みユーザー

退会済みユーザー

2018/10/02 10:45

ご連絡ありがとうございます。 htmlリンク部分とdoGet、setterを修正して動作確認致しましたが、やはりN列への書き込みだけが上手く行きません(スプレッドシートIDやシート名も設定しています)。 動作検証までして頂いているという事で、私の方で何かミスしているのかと思いますが。 メール送信やHTMLの表示は問題無いのでsendHtmlMailのスクリプトは問題無いのだろうと思います。 トリガーは関数sendHtmlMailに対して「フォーム送信時」に設定し、それ以外は特に設定していません。 私の方でミスが無いかもう少し確認します。
退会済みユーザー

退会済みユーザー

2018/10/02 10:51

追記: タイトル行(1行目)のN列以降(N列、O列、P列、Q列・・・)に、手動で何か記入されている場合、何か悪さをする可能性はあるでしょうか?
papinianus

2018/10/02 12:11

N列以降は関係ないです。webアプリケーションを公開するで更新していますか? メールに展開されているリンクのexec以降を提示していただけませんか?(okかngと時刻だけなので公開可能だと思うのですが…)
退会済みユーザー

退会済みユーザー

2018/10/03 03:05

WEBアプリケーションの公開は実施しております。 質問欄のスクリプトの記述を最新の内容に更新させて頂きました。 >メールに展開されているリンクのexec以降を提示していただけませんか? 以下の部分のexec以降の事でしょうか。 exec以降はご教示頂いた内容のまま変更しておりません。exec以降の部分は環境に応じて変更が 必要なのでしょうか?理解不足で申し訳ありません。 (*****の部分はWEB公開の際に表示されるURLを記入しております) html += '<a href="https://*****/exec?p=ok&t='+(timeStamp - 0)+'">承認</a><br>'; html += '<a href="https://*****/exec?p=ng&t='+(timeStamp - 0)+'">否認</a><br>';
papinianus

2018/10/03 03:49

コードをかえる必要はないです。 そうではなくて、実際に表示されたものです。メールに(メールに来るんじゃなかったですっけ?)
退会済みユーザー

退会済みユーザー

2018/10/03 05:44

意図する回答になっているか分かりませんが、send_email.gsのスクリプトの中に記載しております、以下の内容がメール本文に記述されます。 ーーーーーーーーーーーーーーーーーーーーーーーーー /* メール本文 */ var html = "備品購入申請がありますので承認をお願い致します。<br><br>"; ・・・・・・ ・・・・・・ html += "承認しますか?<br><br>"; /* 承認・否認 */ html += '<a href="https://**/exec?p=ok&t='+(timeStamp - 0)+'">承認</a><br>'; html += '<a href="https://**/exec?p=ng&t='+(timeStamp - 0)+'">否認</a><br>'; ーーーーーーーーーーーーーーーーーーーーーーーーー 実際のメール本文の表示は以下のような内容です。 備品購入申請がありますので承認をお願い致します。 申請内容 購入者 氏名:** 商品名:** 数量:1 単価(税込み):2000円 購入理由:*** 購入先(URL等):*** 優先度:Low タイムスタンプ:2018/10/03 11:56:04 承認しますか? 承認 否認 ーーーーーーーーー 承認、否認にリンクが設定されており、クリックするとhttps://*****/execに指定されたリンク先のHTML(ok.html 若しくはng.html)を表示します。 不足があればご教示ください。
papinianus

2018/10/03 05:55

そこの「承認」「否認」っていう文字はリンクになっていますよね、その内容なのですが。 あるいはそこから開いたときの、ブラウザに表示されているurl文字列のexecより後の部分が知りたいです。
退会済みユーザー

退会済みユーザー

2018/10/03 06:24

承認・否認のリンク先のURLは以下の様に表示されております。 (承認)https://*****/exec?p=ok&t=NaN (否認)https://*****/exec?p=ng&t=NaN
papinianus

2018/10/03 07:11

NaNですか。 `(timeStamp - 0)`を`Number(timeStamp)`としていかがでしょうか? →リンクが正しくないので、リンクだけで確認してきただきたいです
退会済みユーザー

退会済みユーザー

2018/10/03 07:59

html += '<a href="https://*****/exec?p=ok&t='+Number(timeStamp)+'">承認</a><br>'; リンク部を上記の様に変更しましたが上手く行きませんでした。リンク先のURLも同じような表示でした。 https://*****/exec?p=ok&t=NaN https://*****/exec?p=ng&t=NaN
papinianus

2018/10/03 09:20 編集

以前に、macaron_xxxさんがおっしゃってた意味を誤解していました。 e.namedValue['タイムスタンプ']は、それ自身文字列なのですね(日付ではない) 私の検証は、formが書き込まれるシート側でやっていたので、動いていました。 再度書き直します。
papinianus

2018/10/03 09:20

書き直しました。 まず、htmlのところはtimeStampだけに戻しました(NaNでないことを見てください) val[1][0]をメールで提示された形式に変換して、一致するような形式にしてみました。
退会済みユーザー

退会済みユーザー

2018/10/03 12:01

確認させていただきました。 〇、×の入力はやはり上手く出来ていないようですが、exec以降は以下のようになっております。 exec?p=ok&t=2018/10/03%2020:42:15 exec?p=ng&t=2018/10/03%2020:42:15 ちなみにこの時のスプレッドシート上、及びメール本文に記載されているタイムスタンプは、 2018/10/03 20:42:15 です。 日付と時刻の間の半角スペースが原因でしょうか?
退会済みユーザー

退会済みユーザー

2018/10/12 08:47

URLの中での半角スペースは”%20”になるようですね。という事はこの部分は意図した動作になっているという事でしょうか。
papinianus

2018/10/15 01:06

反応が遅くなって申し訳ないです。%20については、前回の書き直し時点で考慮していました。調査なさったとおり、URLにするとき一部の記号は%で続く表記になります(GASの場合、勝手になると思ってください)。ただ読み取るときも勝手にスペースに戻り、あまり問題にならないので特に断っていませんでした。 何度かテストしてみたところで、提示コードのうち、setterのforのところで、0からはじめていると、Utilities.formatDataがエラーになる可能性があるので1にあらためました。 あらためて確認しましたが、http://なんたらかんたらt=2018/11/11%2010:20:30となっていても、doGetで見たときは特になにもしなくても(少なくともこちらの環境では)"2018/11/11 10:20:30"に戻っておりました。
退会済みユーザー

退会済みユーザー

2018/10/16 06:56

度々ありがとうございます。 動作確認させて頂きましたがやはり〇×の書き込みは上手く行きませんでした。 何か環境による違いもあるのでしょうか。もう少し動作確認させて頂きます。
papinianus

2018/10/17 04:02

何度も紆余曲折させてしまって申し訳なくまたそのことが上手く行かない原因なのは理解しておりますので、 sendmail.gsとdoGet.gsの最新状態を質問に追記していただくことはできませんでしょうか?
退会済みユーザー

退会済みユーザー

2018/10/17 04:54

こちらこそ長らくサポート頂きありがとうございます。 コードを最新の状態に更新させて頂きました。ご確認の程お願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問