トラブル記録: 朝の授業確認が前日の人に飛ぶ.
前日の授業確認が今日も来てます.という報告が届いて送信済みメールをみたら報告の通り前日の授業確認が出ていて今日のが出ていなかった.
(8/31なのに8/30の授業確認メールが行っていた)
Reminderプロジェクトの方に関数を動かしたばかりだったのでミスったかと思ったが,
var today = new Date(); var dateOfToday=today.getDate();
のように日付は自動で今日の日付を取得していてコードは変更していないのでなぜかわからんかった.
実際に(メールは飛ばさないようにしてから)動かしてみると30日の分が動いた.
一つずつ出力した変数の中身出していったら最終的にここまでさかのぼっていて,
var today = new Date(); var dateOfToday=today.getDate();
これが30日,と判断していた.恐ろしい.
ログを見ると Thu Aug 30 22:50:10 GMT+00:00 2018
.なんで時間違うのかとよくみたらGMT+00:00.
東京時間になっていない.
結論
Reminderプロジェクトを新たに作成したらなぜかスクリプトがイギリス基準になっていて,朝6時のリマインダではまだイギリスは30日だったため30日のリマインダーが飛んでいた.
解決
[プロジェクトのプロパティ] > [タイムゾーン]
の設定を変更し日本時間として,無事に日本時間に直った.
授業管理シート内スクリプト 説明
はじめに
関数の呼ばれ方
他の関数から呼ばれてもいない関数はどこから呼ばれているのか. 関数が隠れている場所の見つけ方.
大きくわけてタイプは以下の3つ.
- ボタン: 右クリックメニューで紐づけされている.
- 上部メニューをプログラムから生成: "aboutUI.gs"プログラムで紐づけ.
- タイムトリガー: 紐付けられているアカウントでしか確認できないことに注意.
スクリプトのある場所
授業管理シートとかの上部メニュー「ツール」 > 「スクリプトエディタ」
以下,現時点でのプロジェクト別にそれぞれの関数の説明.
「Database」
授業管理シート自体の管理のためのスクリプト.データベースを管理するためのスクリプト.データの出し入れを扱う.
管理として以下の4つに大別される.
- シートの新規作成
- 授業の追加
- 授業の変更: 代講.
- 授業の削除: (実際に消す,という処理はしない.)休講/直前キャンセルのセッティング.
CreateMonthSheet.gs
- 月次シート作成
- [紐づけ] aboutUIで上部メニューに挿入.
AddClass.gs
- 作成済み月次シートの授業の追加
- [紐づけ] aboutUIで上部メニューに挿入.
ChangeTeacher.gs
- 代講
- [紐づけ] ボタン
実際は代講用のSSが判断してやってる.
setKyuukou.gs
- 休講のセッティング
- [紐づけ] aboutUIで上部メニューに挿入.
「Reminder」
MorningReminder.gs
daylyMail関数が,何故か伝統的にスペルが間違っているスクリプト.なぜかは知らないが訂正しない.
- 朝の授業リマインド
- [紐づけ] タイムトリガー by tna.reminderアカウント
TaskReminder.gs
- angry bot
- [紐づけ] タイムトリガー by tna.angryアカウント
ReportCheck.gs
- スタッフ講師の拠点リーダーに毎日レポートを送信しているぽい.必要?
- [紐づけ] タイムトリガー by tna.teachersアカウント
「Search」
授業管理シート以外のSSに接続する必要のある検索用のスクリプト
DailyReport.gs
- 授業レポート閲覧用
- [紐づけ] ボタン
Alternative.gs
- 代講依頼閲覧用
- [紐づけ] ボタン
「Tools」
便利機能のためのスクリプト
confirm_myclasses.gs
- 「シフト確認シート」用スクリプト
- [紐づけ] ボタン
createReport.gs
- レポート記入する際に管理シートから判断できる内容については自動で入力できる便利機能.
- [紐づけ] ボタン
displayRobot.gs
- ロボットチームに頼まれて作成したスクリプト
- [紐づけ] aboutUIで上部メニューに挿入.
kyotenReport.gs
「各所レポート作成」
挙動としては授業管理シートの'daiyReport'というシートに報告を穴埋めして,複製,シート名をつける.'dailyReport'を最後にクリア
- 経理さんが月に一度使用
- [紐づけ] aboutUIで上部メニューに挿入.
コードを増やす際の注意.
基本的におこなう内容によって,カテゴリ別に プロジェクト を分けて管理してほしい.どこに何があるのか引き継いでいくシステム担当の人がわからんくなる.
その中で機能ごとに ファイル を分けてほしい.イメージとしては1つのファイルに1説明つくような感じ.
その1つのファイル内でも1関数でごちゃごちゃ書くんじゃなくて,同じ処理はまとめて 関数 にするとか,関数にすることで1つの意味付け,名前付けするとかにしてほしい.
最終的にはなにか探したいときにツリー状に迷わず探しに行ける感じの雰囲気の構成を目標にするイメージ.
コードの整理記録
- 「Manage」プロジェクトを「Database」プロジェクトに名前変更.
- 少しManageだと意味合いが大きすぎるため.あくまでデータの作成や変更のためのプロジェクト
- 「Reminder」プロジェクトを作成.
- 元「Manage/code.gs」にあったもののカテゴリに依るコードの移動を行った.
- daylyMailを「Reminder」に移動.
- alertMailを「Reminder」に移動.
- reportcheckを「Reminder」に移動
- fill_in_the_BlanksをChangeTeacher.gs部分に移動.
- grilLineをCreateMonthSheetの部分に移動.
- makedailyreportを「Tools」に移動.また,上部メニューについて「経理」というメニューに各所レポート作成は移動.
すべてのコードが整理し終わってから引継ぎのドキュメントは改めて書き直します.
基本文法以外のgoogle apps scriptの特有の関数などについて.
google apps script (のうちのspreadsheet系) 主要概念.
この4つの概念の理解が肝.この4つの階層構造理解したらあとは関数とかそのたびに調べられるようになると思う.
最後に例といっしょに説明も入れておく.
- SpreadsheetApp: googleが提供するスプレッドシートのアプリオブジェクト.デフォルトでこのオブジェクトの変数は最初から使用可能.
- Spreadsheet: 授業管理シートのような1つのファイル概念.SpreadsheetAppから取得することが多い.
- Sheet: Spreadsheet内の1枚のシート概念.Spreadsheetオブジェクトから取得してくることが多い.
- Range: Sheet内の複数もしくは単一セルの概念.Sheetオブジェクトから取得してくることが多い.
また,'Active'という表現でいきなり,SpreadsheetAppからもっとRangeオブジェクトを取得したりすることも多い.
よく使う関数の流れ
SpreadsheetApp -> Spreadsheetオブジェクトの取得
SpreadsheetAppという変数は既存で用意されているのでいきなりあるものとしてコード内で使用できる.
ss = SpreadsheetApp.getActiveSpreadsheet()
- そのスクリプトが紐付けられている(Activeな)Spreadsheetを自動的に取得.
授業管理シートに紐付いているスクリプトでこの関数を使用すれば「授業管理シート」というSpreadsheetオブジェクトを取得することになる.
ss= SpreadsheetApp.openById('~~~~')
- ファイル固有のidからSpreadsheetを取得.
ファイル固有のidは https://docs.google.com/spreadsheets/d/1YEsETCQeY30uDvgzc0xFP2ZgMOPrdAwpalm_UsNSihs/edit#gid=70051544っていうURLがあるとしたら,
1YEsETCQeY30uDvgzc0xFP2ZgMOPrdAwpalm_UsNSihs
っていうdのうしろにあるやつ.
補足
上のようにSpreadsheetApp.getActiveSpreadsheet()
とかみたいに,「. (ドット)」で繋がれているものはその前のオブジェクトに属する関数.という感じ.
getActiveSpreadsheet()という関数は「Spreadsheetオブジェクトを取得するための,SpreadsheetAppオブジェクトに属する関数」であって,それによって返ってくるSpreadsheetオブジェクトを ssという変数に代入している. ssは要するに取得されたSpreadsheetオブジェクト.(授業管理シートオブジェクトであることが多い)
Spreadsheet -> Sheetオブジェクトの取得
ssってのは上で取得した何らかのSpreadsheetオブジェクト. そこから中身のシートとかを取得できる.
sheet = ss.getSheetByName('~~~')
- シートの名前からSheetオブジェクトを取得.
'8月'とか,特定のSheetオブジェクトを取ってくる.
sheets = ss.getSheets()
- シートをすべて取得.SheetオブジェクトのリストがSpreadsheet内の順番通りに得られる.配列と同じようにそれぞれにアクセス.
sheets[0], sheets[1]とかがそれぞれSheetオブジェクトとなる.
Sheet -> Rangeを取得
取得後,そのRangeから値を取得したりそのRangeに値をセットしたり色を付けたり.複数セルのときもあれば単一セルのときもあれば.
range = sheet.getRange(row, column, numRows, numColumns) values = range.getValues() color = range.getBackground() range.setValues(セットしたい値) range.setBackground(セットしたい色) range.setFontColor(セットしたい色)
Tutorial
コードを自分で読むための関数の調べ方などのデモ.
上に書いたのは基本的な関数だけど,この階層構造を知ってたら,どのレベルのオブジェクトに属する関数か理解できるので,そのオブジェクトを調べればそこに該当の関数があるはず.なければ多分何かを読み間違えてる.んで説明がサイトに載ってるからそれを調べればコードは読めると思う.
リンク:
- SpreadsheetApp: https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app
- Spreadsheet: https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet
- Sheet: https://developers.google.com/apps-script/reference/spreadsheet/sheet
- Range: https://developers.google.com/apps-script/reference/spreadsheet/range
簡単なコードの例として休講をセッティングするためだけのコードとともに.以下,現時点でのそのままのコピペ.
function setKyuukou() { setStatus('休講') } function setCancel() { setStatus('直前キャンセル') } function setStatus(status){ // status = '休講' or '直前キャンセル', 複数行対応 var activeRange = SpreadsheetApp.getActiveRange() var rowIndex = activeRange.getRowIndex() var height = activeRange.getHeight() for(var i=0; i<height; i++){ var curIndex = rowIndex+i var class_id = SpreadsheetApp.getActiveSheet().getRange(curIndex, 1).getValue() var ui = SpreadsheetApp.getUi() var confirm = ui.alert('授業idが'+String(class_id)+'の授業を'+status+'とします.よろしいですか?', ui.ButtonSet.OK_CANCEL) if(confirm == ui.Button.OK){ SpreadsheetApp.getActiveSheet().getRange(curIndex, 8, 1, 1).setValue('休講') SpreadsheetApp.getActiveSheet().getRange(curIndex, 9, 1, 1).setValue(status) } } }
var activeRange = SpreadsheetApp.getActiveRange()
SpreadsheetAppから取得しているからSpreadsheetオブジェクト,とはならない.この関数を調べてみる.(自分でも上記リンクから調べてみて.)
SpreadsheetAppオブジェクトに繋がれている関数なので,SpreadsheetAppのページからgetActiveRange()
という関数を調べる.(command+Fとかやるといいよ)
すると見つかるはず.
まず,Return (返り値のこと) のところに Range
とかいてある.この関数によって返ってくるのは Rangeオブジェクト.
サイト内の具体例ではその後そのRangeの背景色を取得する関数をそのまま続けている.
ちなみにActiveなRangeとは選択中のセルのこと.休講セッティング関数は休講にしたい行にいた状態で使うというものになっていたはず.ここから来てる.
var rowIndex = activeRange.getRowIndex()
2行目.activeRangeは1行目で代入したRangeオブジェクト.(おそらく名前的にその行の番号を取得するのはわかるだろうが.)
getRowIndex()
関数はRangeオブジェクトに属する関数であることが判断できるので Rangeのページから getRowIndex()
という関数を調べる.見つかるはず.
ReturnはInteger.普通にjavascriptの数値が返ってくる.まぁ想像通りRangeの行番号が返ってくる.
他にはgetRow()関数と同じと書いてあったり.(どちらを使用してもいいけど可読性の高いgetRowIndex()を使って書いた)
こんな感じで調べるといいと思う.一応練習用に続きの解説.
var height = activeRange.getHeight()
rangeから高さを取得して,その高さ分のfor文を回す.
for(var i=0; i<height; i++){ var curIndex = rowIndex+i
セルの行番号に iを足して行番号を順番に取得して,
var class_id = SpreadsheetApp.getActiveSheet().getRange(curIndex, 1).getValue()
その行番号の行の1列目(授業idのはいってる列)のRangeを取得して中の値を取得して,
var ui = SpreadsheetApp.getUi() var confirm = ui.alert('授業idが'+String(class_id)+'の授業を'+status+'とします.よろしいですか?', ui.ButtonSet.OK_CANCEL)
休講にしちゃうけどいいかみたいな確認とって,OKなら,休講/直前キャンセルを該当の場所に取得しちゃう.
if(confirm == ui.Button.OK){ SpreadsheetApp.getActiveSheet().getRange(curIndex, 8).setValue('休講') SpreadsheetApp.getActiveSheet().getRange(curIndex, 9).setValue(status) } } }
授業管理シート内スクリプト 現時点での引継ぎ
追記 (8.30)
いくつかコードの整理を行った. tna-system-memo.hatenadiary.com
コードの整理後改めてドキュメント書いた
tna-system-memo.hatenadiary.com
はじめに
関数の呼ばれ方
他の関数から呼ばれてもいない関数はどこから呼ばれているのか. 関数が隠れている場所の見つけ方.
大きくわけてタイプは以下の3つ.
- ボタン: 右クリックメニューで紐づけされている.
- 上部メニューをプログラムから生成: "aboutUI.gs"プログラムで紐づけ.
- タイムトリガー: 紐付けられているアカウントでしか確認できないことに注意.
スクリプトのある場所
授業管理シートとかの上部メニュー「ツール」 > 「スクリプトエディタ」
以下,現時点でのプロジェクト別にそれぞれの関数の説明.
「Manage」
(>>「Database」という名前に変更したい.)
授業管理シート自体の管理のためのスクリプト.データベースを管理するためのスクリプト.データの出し入れを扱う.
管理として以下の4つに大別される.
- シートの新規作成
- 授業の追加
- 授業の変更: 代講.
- 授業の削除: (実際に消す,という処理はしない.)休講/直前キャンセルのセッティング.
code.gs
最下部に記述,そちらを参照.
CreateMonthSheet.gs
- 月次シート作成
- 紐づけ: aboutUIで上部メニューに挿入.
AddClass.gs
- 作成済み月次シートの授業の追加
- 紐づけ: aboutUIで上部メニューに挿入.
ChangeTeacher.gs
- 代講
- 紐づけ: ボタン
実際は代講用のSSが判断してやってる.
setKyuukou.gs
- 休講のセッティング
- 紐づけ: aboutUIで上部メニューに挿入.
「Search」
授業管理シート以外のSSに接続する必要のある検索用のスクリプト
DailyReport.gs
- 授業レポート閲覧用
- 紐づけ: ボタン
Alternative.gs
- 代講依頼閲覧用
- 紐づけ: ボタン
「Tools」
便利機能のためのスクリプト
confirm_myclasses.gs
- 「シフト確認シート」用スクリプト
- 紐づけ: ボタン
createReport.gs
- レポート記入する際に管理シートから判断できる内容については自動で入力できる便利機能.
- 紐づけ: ボタン
displayRobot.gs
- ロボットチームに頼まれて作成したスクリプト
- 紐づけ: aboutUIで上部メニューに挿入.
Manage/code.gsについて
まだ整理しきれていないコード.必要な物,不要なものが混在する. 丁寧に切り分けていく.
また,整理の際に削除した関数は以下.丁寧に切り分けたが,なにか起こってしまったら少しここを疑うこと.確認した上で必要だったら去年のやつからコピペで戻す.
- makeReport
- samplealert
- ClassConfirmOffPost
- weeklyReport: facebook投稿もうしなくなったらしいので.
- alertToMakeWeeklyReport
- transportbreak: これ以下の方全て重要そうだがどこでも使ってなさそうで消してしもた.
- TransportPlaceCheck
- TransportRequest
- TransportRequestDelete
- transportCheck
checkdailyreport
紐づけ: タイムトリガー by tnal.teachersアカウント
今日の日付までで、授業レポートが提出されているか確認する。
- N列目に[未記入][記入済み]入れる謎の関数.N列目を見ているプログラムはない気が.
- 挙動的にはI列を使うわけでもなく,ans_ssからわざわざとってきている
N列目を使用しているものがなければ削除してもいい. 【経理の方がN列目を閲覧している可能性あり】
makedailyreport >> 「Tools」プロジェクトに移動予定
「各所レポート作成」
挙動としては授業管理シートの'daiyReport'というシートに報告を穴埋めして,複製,シート名をつける.'dailyReport'を最後にクリア
- 経理さんが月に一度使用
- 紐づけ: aboutUIで上部メニューに挿入.
daylyMail >> 「Reminder」プロジェクトに移動予定
何故か伝統的にスペルが間違っているスクリプト.なぜかは知らないが訂正しない.
- 朝の授業リマインド
- 紐づけ: タイムトリガー by tna.reminderアカウント
alertMail >> 「Reminder」プロジェクトに移動予定
- angry bot
- 紐づけ: タイムトリガー by tna.angryアカウント
ReportCheck >> 「Reminder」プロジェクトに移動予定
- スタッフ講師の拠点リーダーに毎日レポートを送信しているぽい.必要?
- 紐づけ: タイムトリガー by tna.teachersアカウント
gridLine >> 月次シート作成のところに移動予定.
- 枠線表示のプログラム(毎日更新用)
- 紐づけ: タイムトリガー by tna.teachersアカウント
- 【正直タイムトリガーである必要はないと思われる.崩れてるときに上部メニューから使用だけでよい.】
gridLine2 >> 月次シートのところに移動予定.
- 枠線表示のプログラム(月次シート作成のときに呼ばれる.)
fill_in_the_Blanks >> 代講のところに移動予定.
- Q列の教室分類を書き込む
- 紐づけ: タイムトリガー by tna.teachersアカウント
Q列は,代講の場所のチェックで重複がないか確認するために使用している.
コードを増やす際の注意.
基本的におこなう内容によって,カテゴリ別に プロジェクト を分けて管理してほしい.どこに何があるのか引き継いでいくシステム担当の人がわからんくなる.
その中で機能ごとに ファイル を分けてほしい.イメージとしては1つのファイルに1説明つくような感じ.
その1つのファイル内でも1関数でごちゃごちゃ書くんじゃなくて,同じ処理はまとめて 関数 にするとか,関数にすることで1つの意味付け,名前付けするとかにしてほしい.
最終的にはなにか探したいときにツリー状に迷わず探しに行ける感じの雰囲気の構成を目標にするイメージ.