[GAS][slack]営業日カウントダウンbotを作っている途中 その5 やっとこさクラス化していくぞ
前回
クラス化の前に、クラスで生成したあとのメソッドの変更とかアロー関数に寄り道していた。そのへんの理解も深まってよかった。
いま気になっていること
クラス化
emoji-codeでもアイコンいけるんじゃないの?
webhoook
カレンダ 祝日+土日+指定休日の統合
スクリプトファイルの並び順 https://developers.google.com/apps-script/releases
現在のコード構成
各functionに分けたので、テストもしやすくなった。
いまはスプシから通知データを持ってくるようになっていたりと、
色々と思うところはあるが、とにかくまずはクラス化していくぞ。
main
/**
* 最終更新日 2022/4/15
* 更新者 XXXX
*
* トリガーアカウント: XXXX@gmail.com
* 実行スクリプト:main
* トリガーイベント:例: 時間主導型 / 日付ベースのタイマー / 1日 / 午前 7 時~8 時
*
* @param {Date} Date - 今日の日付(globalから)
*/
function main() {
//平日のみslackに投稿する用の日付判定用の別関数呼び出し、土日祝ならここで処理終了
if (isWorkday(today) == false) {
return;
}
//土日祝でないならslacに投稿投稿
else {
postSlackbot()
}
}
postSlackbot
メッセージ内で使用する日付、残営業日数は、今はスプレッドシートから持ってきているが、これもGASで計算させてもいいかもしれない?
/**
* 参考
* https://auto-worker.com/blog/?p=2904#
*
* 参考 プロパティストア
* https://tonari-it.com/gas-property-store/
*
* 参考 GASでSlackAPIが使えるライブラリ
* https://blog.guchimina.com/?p=370
* https://github.com/soundTricker/SlackApp
*
* スプレッドシートで計算した残営業日を取得してslackで通知する。
*/
function postSlackbot() {
//SlackAPIで登録したボットのトークンを設定する
const token = PropertiesService.getScriptProperties().getProperty('SLACK_TOKEN');
//ライブラリから導入したSlackAppを定義し、トークンを設定する
const slackApp = SlackApp.create(token);
//Slackボットがメッセージを投稿するチャンネルを定義する
const channelId = "#general";
//メッセージ内で使用する日付、残営業日数を定義する
const todayFromSheet = dateMasterSheet.getRange('D2').getDisplayValue();
const businessDaysRemainingThisMonth = dateMasterSheet.getRange('D28').getValue();
const businessDaysRemainingInThisYear = dateMasterSheet.getRange('D29').getValue();
const businessDaysRemainingInThisFiscalYear = dateMasterSheet.getRange('D30').getValue();
//Slackボットが投稿するメッセージを定義する
const message = `
今日は ${todayFromSheet} です。
今月の残り営業日数は あと ${businessDaysRemainingThisMonth} 日です。
今年の残り営業日数は あと ${businessDaysRemainingInThisYear} 日です。
今年度の残り営業日数は あと ${businessDaysRemainingInThisFiscalYear} 日です。
`
const iconImage = "http://flat-icon-design.com/f/f_business_23/s256_f_business_23_0bg.png";
const options = {
// channelId: slackUserID, //チャンネル名
botUserName: "GASdeName", //投稿するbotの名前
// message: statusMessage, //投稿するメッセージ
bot_icon: iconImage //投稿時に表示されるアイコン
};
// console.log(options.botUserName);
//SlackAppオブジェクトのpostMessageメソッドでボット投稿を行う
slackApp.postMessage(channelId, message, { username: options.botUserName, icon_url: options.bot_icon });
}
isWorkday
/**
* 最終更新日 2022/4/15
* @param {Date} targetDate = 今日の日付
* @return {Boolean} 土日祝+指定の休日かどうかを判定 true=営業日
* 参考
* https://dev.classmethod.jp/articles/202001-workday-only-gas/
*/
function isWorkday(targetDate) {
// function isWorkday(targetDate = new Date('2022/12/30') {
// targetDate の曜日を確認、週末は休む (false)
if (isRestDay(targetDate) === true) { return; }
// 祝日カレンダーを確認する
if (isJapaneaseHoliday(targetDate) === true) { return; }
//会社指定の休日(上記の祝日カレンダには入っていない休日、休暇)スプレッドシートから取得
if (isCompanyHoliday(targetDate) === true) { return; }
// 全て当てはまらなければ営業日 (True)
console.log(`今日は 営業日ですよ`);
return true;
}
isRestDay
/**
* targetDate の曜日を確認、週末は休む (true)
* @param {Date} Date - 今日の日付
* @return {boolean} boolean - 今日が土日なら true を返す
*/
function isRestDay(targetDate) {
const rest_or_work = ["REST", "mon", "tue", "wed", "thu", "fri", "REST"]; // 日〜土
if (rest_or_work[targetDate.getDay()] == "REST") {
console.log(`今日は 土日ですよ`);
return true;
}
}
isJapaneaseHoliday
/**
* targetDate の曜日を確認、祝祭日は休む (true)
* @param {Date} Date - 今日の日付
* @return {boolean} boolean - 今日が祝祭日なら true を返す
*/
function isJapaneaseHoliday(targetDate) {
const calJpHolidayUrl = "ja.japanese#holiday@group.v.calendar.google.com";
const calJpHoliday = CalendarApp.getCalendarById(calJpHolidayUrl);
if (calJpHoliday.getEventsForDay(targetDate).length != 0) {
// その日に予定がなにか入っている = 祝祭日 = 営業日じゃない (false)
console.log(`今日は 祝日ですよ`);
return true;
};
}
isCompanyHoliday
/**
* targetDate の曜日を確認、会社の指定休日は休む (true)
* @param {Date} Date - 今日の日付
* @return {boolean} boolean - 今日が会社の指定休日なら true を返す
*/
function isCompanyHoliday(targetDate) {
//会社指定の休日をスプレッドシートから取得
const winterHoliday1 = dateMasterSheet.getRange('D31').getValue().getTime();
const winterHoliday2 = dateMasterSheet.getRange('D32').getValue().getTime();
const winterHoliday3 = dateMasterSheet.getRange('D33').getValue().getTime();
//会社指定の休日を配列に格納
const winterHolidays = [winterHoliday1, winterHoliday2, winterHoliday3];
//winterHolidays に targetDate が含まれていたら true
if (winterHolidays.includes(targetDate.getTime()) == true) {
//targetDate が冬季休暇日だったらfalse
console.log(`今日は 冬季休日ですよ`);
return true;
}
}
gobal
/**
* GitHub README.md
* https://github.com/FrontWorks-Inc/blog_list-of-holidays
*/
/**
* グローバル定数宣言
*/
/** @type {SpreadsheetApp.Spreadsheet} */
const holidaySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('祝日リスト');
const dateMasterSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('日付マスタ');
const today = new Date();
クラス化する
各functionに分けたから、クラスのメソッドはできてる、やりやすくなってる。
クラスのconstructorに入れる引数をどうするかだ。
そーちゃんのブログに書いてあるわけだが、ちゃんと理解して、車輪の再発明でも写経でも、なんでもいいから、とにかく、腑に落ちたい。理解したい。
これらをクラス化していくぞ。
各functionに渡しているdateとdateMasterSheetをconstructorの引数に持たせて、メソッドに色々入れて、インスタンス生成していく、という流れでよい、のか? isXXX系をまとめていくぞ。
クラス 構文
class クラス名{
//クラス定義の内容
}
構文だけみても正直あんまりピンとこないので、例をみたほうがわかる。
クラス 例
https://tonari-it.com/gas-class-method-prototype/ より
function myFunction() {
class Person {
constructor(name) {
this.name = name;
}
greet() {
Browser.msgBox(this.name + "です、こんにちは!");
}
}
const p = new Person('Bob');
p.greet();
const q = new Person('Tom');
q.greet();
}
constructorメソッド
constructor([arguments]) { ... }
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes/constructor
で、今回の日付関係のクラス、まずはこんな感じか?
/**
* 日付に関するクラス
*/
class Day {
/**
* @param {Date} targetDate - 日付
* @param {object} dateMasterSheet - シート
*/
constructor(targetDate = new Date(), dateMasterSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('日付マスタ')) {
this.targetDate = targetDate;
this.dateMasterSheet = dateMasterSheet;
}
}
function testDay() {
const nd = new Day();
console.log(nd.targetDate);
console.log(nd.dateMasterSheet.getName());
}
function testDay で、インスタンスが生成されていることを確認。
最初、クラスのコンストラクタを
constructor(targetDate, dateMasterSheet) としていて、undifindになってあっれ~~~???となっていた。
あ~~~やっぱこれ、祝日や営業日もクラス化したくなってくるな…...。
で、Class etau (えとうさんの作成した各種クラス)の利用になってくるのか……悔しいのでまずは自分のクラスを完成させるぞ。
まずはメソッドをひとつ追加して、ログ確認だ。
function をそのままコピペして、function宣言消して、整えればできそう。

うーん、でもそのままではだめっぽそう。
const nd = new Day();
const getTime = nd.targetDate.getTime(); console.log(getTime);
みたいに、インスタンス(オブジェクト)から取り出さないとじゃん?
で、それをクラスに持たせるメソッドには???あれ???
if (winterHolidays.includes(this.targetDate.getTime()) == true) {
でいいのか?
あ、よさそう、そかそか、そんな感じか??
オブジェクトの取り出しか。this大活躍だな。
途中のコード
いまんとこうまくいってる、はず。忘れがち、ifのthisよ。これthis入れ忘れてエラー出たりする。
/**
* 日付に関するクラス
*/
class Day {
/**
* @param {Date} targetDate - 日付
* @param {object} dateMasterSheet - シート
*/
constructor(targetDate = new Date('2022/12/30'), dateMasterSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('日付マスタ')) {
this.targetDate = targetDate;
this.dateMasterSheet = dateMasterSheet;
}
/**
* targetDate の曜日を確認、祝祭日は休む (true)
* @param {Date} Date - 今日の日付
* @return {boolean} boolean - 今日が祝祭日なら true を返す
*/
isJapaneaseHoliday(targetDate) {
const calJpHolidayUrl = "ja.japanese#holiday@group.v.calendar.google.com";
const calJpHoliday = CalendarApp.getCalendarById(calJpHolidayUrl);
if (calJpHoliday.getEventsForDay(this.targetDate).length != 0) {
// その日に予定がなにか入っている = 祝祭日 = 営業日じゃない (false)
console.log(`今日は 祝日ですよ`);
return true;
}
}
/**
* targetDate の曜日を確認、会社の指定休日は休む (true)
* @param {targetDate} Date - 今日の日付
* @return {boolean} boolean - 今日が会社の指定休日なら true を返す
*/
isCompanyHoliday(targetDate) {
//会社指定の休日をスプレッドシートから取得
const winterHoliday1 = dateMasterSheet.getRange('D31').getValue().getTime();
const winterHoliday2 = dateMasterSheet.getRange('D32').getValue().getTime();
const winterHoliday3 = dateMasterSheet.getRange('D33').getValue().getTime();
//会社指定の休日を配列に格納
const winterHolidays = [winterHoliday1, winterHoliday2, winterHoliday3];
//winterHolidays に targetDate が含まれていたら true
if (winterHolidays.includes(this.targetDate.getTime()) == true) {
//targetDate が冬季休暇日だったらfalse
console.log(`今日は 冬季休日ですよ`);
return true;
}
}
}
function testDay() {
const nd = new Day();
console.log(nd.targetDate);
console.log(nd.dateMasterSheet.getName());
nd.isCompanyHoliday();
nd.isJapaneaseHoliday();
}
あ~~~
あ~~~いや、違う、違う、引数 = this.targetDate だよな???
ifでも動いちゃってるけど
こうだな??
isRestDay(targetDate = this.targetDate) {
const rest_or_work = ["REST", "mon", "tue", "wed", "thu", "fri", "REST"]; // 日〜土
if (rest_or_work[targetDate.getDay()] == "REST") {
console.log(`今日は 土日ですよ`);
return true;
}
}
う~ん、isWorkday 追加したら、エラー出た。

isRestDay メソッドに持たせたよな?
エラーの出るコード
/**
* 日付に関するクラス
*/
class Day {
/**
* @param {Date} targetDate - 日付
* @param {object} dateMasterSheet - シート
*/
constructor(targetDate = new Date('2022/4/29'), dateMasterSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('日付マスタ')) {
this.targetDate = targetDate;
this.dateMasterSheet = dateMasterSheet;
}
/**
* 最終更新日 2022/4/15
* @param {Date} targetDate = 今日の日付
* @return {Boolean} 土日祝+指定の休日かどうかを判定 true=営業日
* 参考
* https://dev.classmethod.jp/articles/202001-workday-only-gas/
*/
isWorkday(targetDate = this.targetDate) {
console.log({ targetDate });
// targetDate の曜日を確認、週末は休む (false)
if (isRestDay(targetDate) === true) { return; }
// 祝日カレンダーを確認する
if (isJapaneaseHoliday(targetDate) === true) { return; }
//会社指定の休日(上記の祝日カレンダには入っていない休日、休暇)スプレッドシートから取得
if (isCompanyHoliday(targetDate) === true) { return; }
// 全て当てはまらなければ営業日 (True)
console.log(`今日は 営業日ですよ`);
return true;
}
/** targetDate の曜日を確認、週末は休む (true)
* @param {Date} Date - 今日の日付
* @return {boolean} boolean - 今日が土日なら true を返す
*/
isRestDay(targetDate = this.targetDate) {
const rest_or_work = ["REST", "mon", "tue", "wed", "thu", "fri", "REST"]; // 日〜土
if (rest_or_work[targetDate.getDay()] == "REST") {
console.log(`今日は 土日ですよ`);
return true;
} else {
console.log(`今日は 土日じゃないですよ`);
return false;
}
}
/**
* targetDate の曜日を確認、祝祭日は休む (true)
* @param {Date} Date - 今日の日付
* @return {boolean} boolean - 今日が祝祭日なら true を返す
*/
isJapaneaseHoliday(targetDate = this.targetDate) {
const calJpHolidayUrl = "ja.japanese#holiday@group.v.calendar.google.com";
const calJpHoliday = CalendarApp.getCalendarById(calJpHolidayUrl);
if (calJpHoliday.getEventsForDay(targetDate).length != 0) {
// その日に予定がなにか入っている = 祝祭日 = 営業日じゃない (false)
console.log(`今日は 祝日ですよ`);
return true;
} else {
console.log(`今日は 祝日じゃないですよ`);
return false;
}
}
/**
* targetDate の曜日を確認、会社の指定休日は休む (true)
* @param {targetDate} Date - 今日の日付
* @return {boolean} boolean - 今日が会社の指定休日なら true を返す
*/
isCompanyHoliday(targetDate = this.targetDate) {
//会社指定の休日をスプレッドシートから取得
const winterHoliday1 = dateMasterSheet.getRange('D31').getValue().getTime();
const winterHoliday2 = dateMasterSheet.getRange('D32').getValue().getTime();
const winterHoliday3 = dateMasterSheet.getRange('D33').getValue().getTime();
//会社指定の休日を配列に格納
const winterHolidays = [winterHoliday1, winterHoliday2, winterHoliday3];
//winterHolidays に targetDate が含まれていたら true
if (winterHolidays.includes(targetDate.getTime()) == true) {
//targetDate が冬季休暇日だったらfalse
console.log(`今日は 冬季休日ですよ`);
return true;
} else {
console.log(`今日は 冬季休日じゃないですよ`);
return false;
}
}
}//class Day End
function testDay() {
const nd = new Day();
console.log(nd.targetDate);
console.log(nd.dateMasterSheet.getName());
nd.isCompanyHoliday();
nd.isJapaneaseHoliday();
nd.isRestDay();
nd.isWorkday();
}
あっれ~~~?と思って、私の得意技、軽率に質問を実行したところ、もっともな回答を頂戴した

どうもこのへんのことが、やっぱまだ自分に浸透してないんだなー、お恥ずかしい。
一旦クラス化したコード
ひとまず。
main
/**
* 最終更新日 2022/4/20
* 更新者 XXXX
*
* トリガーアカウント: XXXX@gmail.com
* 実行スクリプト:main
* トリガーイベント:例: 時間主導型 / 日付ベースのタイマー / 1日 / 午前 7 時~8 時
*
* @param {Date} Date - 今日の日付(globalから)
*/
function main() {
//クラスから呼び出し
const newDay = new Day();
console.log(newDay.targetDate);
// console.log(newDay.dateMasterSheet.getName());
// newDay.isCompanyHoliday();
// newDay.isJapaneaseHoliday();
// newDay.isRestDay();
// newDay.isWorkday();
//平日のみslackに投稿する用の日付判定用の別関数呼び出し、土日祝ならここで処理終了
if (newDay.isWorkday() === false) {
console.log(`今日は 営業日じゃないのでSlackには投稿しませんでした。`);
return;
}
//土日祝でないならslacに投稿投稿
else {
postSlackbot();
console.log(`今日は 営業日なのでSlackに投稿しました。`);
}
}
postslack
投稿する日付をGASで計算したいかなー。
/**
* 参考
* https://auto-worker.com/blog/?p=2904#
*
* 参考 プロパティストア
* https://tonari-it.com/gas-property-store/
*
* 参考 GASでSlackAPIが使えるライブラリ
* https://blog.guchimina.com/?p=370
* https://github.com/soundTricker/SlackApp
*
* スプレッドシートで計算した残営業日を取得してslackで通知する。
*/
function postSlackbot() {
//SlackAPIで登録したボットのトークンを設定する
const token = PropertiesService.getScriptProperties().getProperty('SLACK_TOKEN');
//ライブラリから導入したSlackAppを定義し、トークンを設定する
const slackApp = SlackApp.create(token);
//Slackボットがメッセージを投稿するチャンネルを定義する
const channelId = "#general";
//メッセージ内で使用する日付、残営業日数を定義する
const todayFromSheet = dateMasterSheet.getRange('D2').getDisplayValue();
const businessDaysRemainingThisMonth = dateMasterSheet.getRange('D28').getValue();
const businessDaysRemainingInThisYear = dateMasterSheet.getRange('D29').getValue();
const businessDaysRemainingInThisFiscalYear = dateMasterSheet.getRange('D30').getValue();
//Slackボットが投稿するメッセージを定義する
const message = `
今日は ${todayFromSheet} です。
今月の残り営業日数は あと ${businessDaysRemainingThisMonth} 日です。
今年の残り営業日数は あと ${businessDaysRemainingInThisYear} 日です。
今年度の残り営業日数は あと ${businessDaysRemainingInThisFiscalYear} 日です。
`
const iconImage = "http://flat-icon-design.com/f/f_business_23/s256_f_business_23_0bg.png";
const options = {
// channelId: slackUserID, //チャンネル名
botUserName: "営業日カウントダウンbotさん", //投稿するbotの名前
// message: statusMessage, //投稿するメッセージ
bot_icon: iconImage //投稿時に表示されるアイコン
};
// console.log(options.botUserName);
//SlackAppオブジェクトのpostMessageメソッドでボット投稿を行う
slackApp.postMessage(channelId, message, { username: options.botUserName, icon_url: options.bot_icon });
}
class day
isCompanyHolidayメソッドをスプシから取得じゃなくてGASで計算したみがある。
/**
* 日付に関するクラス
*/
class Day {
/**
* @param {Date} targetDate - 日付
* @param {object} dateMasterSheet - シート
*/
constructor(targetDate = new Date('2022/12/31'), dateMasterSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('日付マスタ')) {
this.targetDate = targetDate;
this.dateMasterSheet = dateMasterSheet;
}
/**
* 最終更新日 2022/4/15
* @param {Date} targetDate = 今日の日付
* @return {Boolean} 土日祝+指定の休日かどうかを判定 true=営業日
* 参考
* https://dev.classmethod.jp/articles/202001-workday-only-gas/
*/
isWorkday(targetDate = this.targetDate) {
// console.log({ targetDate });
// targetDate の曜日を確認、週末は休む (false)
if (this.isRestDay(targetDate) === true) { return false; }
// 祝日カレンダーを確認する
if (this.isJapaneaseHoliday(targetDate) === true) { return false; }
//会社指定の休日(上記の祝日カレンダには入っていない休日、休暇)スプレッドシートから取得
if (this.isCompanyHoliday(targetDate) === true) { return false; }
// 全て当てはまらなければ営業日 (True)
console.log(`今日は 営業日ですよ`);
return true;
}
/** targetDate の曜日を確認、週末は休む (true)
* @param {Date} Date - 今日の日付
* @return {boolean} boolean - 今日が土日なら true を返す
*/
isRestDay(targetDate = this.targetDate) {
const rest_or_work = ["REST", "mon", "tue", "wed", "thu", "fri", "REST"]; // 日〜土
if (rest_or_work[targetDate.getDay()] == "REST") {
console.log(`今日は 土日ですよ`);
return true;
} else {
console.log(`今日は 土日じゃないですよ`);
return false;
}
}
/**
* targetDate の曜日を確認、祝祭日は休む (true)
* @param {Date} Date - 今日の日付
* @return {boolean} boolean - 今日が祝祭日なら true を返す
*/
isJapaneaseHoliday(targetDate = this.targetDate) {
const calJpHolidayUrl = "ja.japanese#holiday@group.v.calendar.google.com";
const calJpHoliday = CalendarApp.getCalendarById(calJpHolidayUrl);
if (calJpHoliday.getEventsForDay(targetDate).length != 0) {
// その日に予定がなにか入っている = 祝祭日 = 営業日じゃない (false)
console.log(`今日は 祝日ですよ`);
return true;
} else {
console.log(`今日は 祝日じゃないですよ`);
return false;
}
}
/**
* targetDate の曜日を確認、会社の指定休日は休む (true)
* @param {targetDate} Date - 今日の日付
* @return {boolean} boolean - 今日が会社の指定休日なら true を返す
*/
isCompanyHoliday(targetDate = this.targetDate) {
//会社指定の休日をスプレッドシートから取得
const winterHoliday1 = dateMasterSheet.getRange('D31').getValue().getTime();
const winterHoliday2 = dateMasterSheet.getRange('D32').getValue().getTime();
const winterHoliday3 = dateMasterSheet.getRange('D33').getValue().getTime();
//会社指定の休日を配列に格納
const winterHolidays = [winterHoliday1, winterHoliday2, winterHoliday3];
//winterHolidays に targetDate が含まれていたら true
if (winterHolidays.includes(targetDate.getTime()) == true) {
//targetDate が冬季休暇日だったらfalse
console.log(`今日は 冬季休日ですよ`);
return true;
} else {
console.log(`今日は 冬季休日じゃないですよ`);
return false;
}
}
}//class Day End
// function testDay() {
// const nd = new Day();
// console.log(nd.targetDate);
// // console.log(nd.dateMasterSheet.getName());
// // nd.isCompanyHoliday();
// // nd.isJapaneaseHoliday();
// // nd.isRestDay();
// nd.isWorkday();
// }
global
today は消した。GASで計算するようにしたらglobalいらなくなるな。
/**
* https://github.com/FrontWorks-Inc/blog_list-of-holidays
*/
/**
* グローバル定数宣言
*/
/** @type {SpreadsheetApp.Spreadsheet} */
const holidaySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('祝日リスト');
const dateMasterSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('日付マスタ');
いま気になっていること
emoji-codeでもアイコンいけるんじゃないの?
webhoook
SlackAPI ライブラリ ちゃんと理解したい
カレンダ 祝日+土日+指定休日の統合?
スクリプトファイルの並び順 https://developers.google.com/apps-script/releases
会社指定休日をクラスに持たせる?
営業日判定もクラスに持たせる?
スプレッドシートいらなくなる?
いったん、ここまで!
だいぶ進捗した感ある!
やった!
続き
#GAS
#slack
#ノンプロ研
#bot
#class
#クラス
いいなと思ったら応援しよう!
