GASを使ったスプレッドシートからChatworkに自動通知ツール

実現したいこと

実現したいこと
スプレッドシートからChatworkに自動通知させたいです。
毎日9~10時をトリガー自動で実行する仕様にしています。
スプレッドシートE列に入れた実行予定日に基づいて通知を行います。

送りたい日と通知は下記の通りです
① E列に入れた実行予定日と同じ実行日のとき「当日通知」の文章を送る
② E列に入れた実行予定日の前日のとき「前日通知」の文章を送る
※ ただし土日祝日が実行予定日の前日の場合は「前営業日」の文章に変更して送付するイメージです。

また実行後に 実行日時(前日)|| 実行日時(当日)に実行日付を書き込みますが、
書き込まれている部分は再実行をしないようにしたいです。

発生している問題・分からないこと

GASでスプレッドシートからChatworkに自動通知するプログラムを組んでいます。
以下の条件分岐をさせて通知を行いたいのですが、当日通知が送られません。

送りたい日と通知は下記の通りです
① E列に入れた実行予定日と同じ実行日のとき「当日通知」の文章を送る
② E列に入れた実行予定日の前日のとき「前日通知」の文章を送る
※ ただし土日祝日が実行予定日の前日の場合は「前営業日」の文章に変更して送付するイメージです。

スプレッドシートは以下の構成です
実行している日は20230426です

N0. ||ルームID ||通知タイトル ||投稿内容 ||通知トリガー ||実行日時(前日)|| 実行日時(当日)
N0. ||ルームID ||通知タイトル ||投稿内容 ||2024/04/26||         ||
N0. ||ルームID ||通知タイトル ||投稿内容 ||2024/04/30||         ||
N0. ||ルームID ||通知タイトル ||投稿内容 ||2024/05/14||         ||      

該当のソースコード

GAS

1function sendExpenseNotification() { 2 // 現在の日付と時刻を取得 3 const today = new Date(); 4 Logger.log("今日: " + today.toLocaleString("ja-JP")); 5 const holidays = getHolidays(); 6 Logger.log("祝日: " + holidays.join(", ")); 7 8 // スプレッドシート読み込み 9 const ss = SpreadsheetApp.getActiveSpreadsheet(); 10 const sheet = ss.getSheetByName('自動通知'); 11 const lastRow = sheet.getLastRow(); 12 13 // ChatWorkAPIクライアント作成 14 const client = ChatWorkClient.factory({ token: token }); 15 16 // スプレッドシートに記載がある分だけ繰り返す 17 for (var i = 2; i <= lastRow; i++) { 18 const [roomId, messageItem, message, triggerDate, prevDayExecuted, todayExecuted, prevDayExecutedDate, todayExecutedDate] = sheet.getRange(i, 2, 1, 9).getValues()[0]; 19 if (!triggerDate) continue; 20 21 // F列に日付が入っている場合は前日実行済みなのでスキップ 22 if (prevDayExecutedDate) continue; 23 24 // G列に日付が入っている場合は当日実行済みなのでスキップ 25 if (todayExecutedDate) continue; 26 27 const reservationDate = new Date(triggerDate); 28 Logger.log("トリガー日: " + reservationDate.toLocaleString("ja-JP")); 29 30 // 実行日がトリガー日の前営業日より前の日付やトリガー日より後の日付には通知しない 31 const prevWeekday = getPreviousWeekday(today); 32 Logger.log("前営業日: " + prevWeekday.toLocaleString("ja-JP")); 33 if (today < prevWeekday || today >= reservationDate) { 34 continue; 35 } 36 37 // 通知トリガーが実行日の4日前より未来の場合は通知しない 38 const fourDaysBeforeTrigger = new Date(reservationDate); 39 fourDaysBeforeTrigger.setDate(reservationDate.getDate() - 4); 40 Logger.log("通知トリガーの4日前: " + fourDaysBeforeTrigger.toLocaleString("ja-JP")); 41 if (today < fourDaysBeforeTrigger) { 42 continue; 43 } 44 45 // 当日通知実行 46 if ( 47 isSameDate(today, reservationDate) && 48 !todayExecuted && 49 !prevDayExecutedDate && 50 !todayExecutedDate 51 ) { 52 Logger.log("■ 今日は実行日です。"); 53 // 当日通知を送信 54 const todayMsg = `※連絡※【本日は${messageItem}です】\n${message}`; 55 client.sendMessage({ 56 room_id: roomId, 57 body: todayMsg 58 }); 59 // 当日通知実行日時の記録 60 sheet.getRange(i, 7).setValue(today); 61 } 62 63 // 前日通知実行 64 const prevDay = new Date(reservationDate); 65 prevDay.setDate(reservationDate.getDate() - 1); 66 Logger.log("前日: " + prevDay.toLocaleString("ja-JP")); 67 68 // 前日が平日かどうかをチェック 69 const isPrevDayWeekday = isWeekday(prevDay); 70 // 前日が祝日かどうかをチェック 71 const isPrevDayHoliday = isHoliday(prevDay); 72 73 if (isPrevDayWeekday && !isPrevDayHoliday && !prevDayExecuted) { 74 Logger.log("■ 前日は平日のため前日通知日です"); 75 // 平日の場合、前日通知を送信 76 const prevDateMsg = `※連絡※【明日は${messageItem}です】\n${message}`; 77 client.sendMessage({ 78 room_id: roomId, 79 body: prevDateMsg 80 }); 81 // 前日通知実行日時の記録 82 sheet.getRange(i, 6).setValue(today); 83 } else if (!isPrevDayWeekday || isPrevDayHoliday) { 84 Logger.log("■ 前日は土日祝日のため前営業日通知日です"); 85 // 平日でない場合または祝日の場合、前営業日通知を送信 86 const prevWeekdayMsg = `※連絡※【${messageItem}につきまして】当日は休日のため、前営業日(${today.getMonth() + 1}月${today.getDate()}日)に投稿いたします。\n${message}`; 87 client.sendMessage({ 88 room_id: roomId, 89 body: prevWeekdayMsg 90 }); 91 // 前営業日通知実行日時の記録 92 sheet.getRange(i, 6).setValue(today); // 前日の前営業日実行 93 } 94 } 95} 96 97 98//==================================================================// 99// 関数 // 100// =================================================================// 101 102// 日付が同じかどうかを比較する関数 103function isSameDate(date1, date2) { 104 return ( 105 date1.getFullYear() === date2.getFullYear() && 106 date1.getMonth() === date2.getMonth() && 107 date1.getDate() === date2.getDate() 108 ); 109} 110 111 112// 指定された日付が平日かどうかを判定する関数※1が月曜、5が金曜 113function isWeekday(dateToCheck) { 114 const day = dateToCheck.getDay(); 115 return day >= 1 && day <= 5; 116} 117 118 119// 指定された日付が土曜日または日曜日かどうかを判定する関数※ 0が日曜、6が土曜 120function isWeekend(dateToCheck) { 121 const day = dateToCheck.getDay(); 122 return day === 0 || day === 6; 123} 124 125 126// Googleカレンダーから日本の祝日を取得する 127function getJapaneseHolidays() { 128 const calendarId = 'ja.japanese#holiday@group.v.calendar.google.com'; 129 const now = new Date(); // 現在の日付を取 130 const oneYearFromNow = new Date(now.getFullYear() + 1, 0, 1); 131 const events = CalendarApp.getCalendarById(calendarId).getEvents(now, oneYearFromNow); 132 const holidays = events.map(event => event.getDate()); 133 return holidays; 134} 135function getHolidays() { 136 const now = new Date(); 137 const oneYearFromNow = new Date(now.getFullYear() + 1, 0, 1); 138 // 日本の祝日カレンダーのIDを定義 139 const holidayCalendarId = 'ja.japanese#holiday@group.v.calendar.google.com'; 140 const calendar = CalendarApp.getCalendarById(holidayCalendarId); 141 const holidays = calendar.getEvents(now, oneYearFromNow); 142 143 const holidayDates = []; 144 145 // 各イベント(祝日)について繰り返し処理 146 for (const holiday of holidays) { 147 // 祝日の日付を取得し、日本のタイムゾーンで"yyyy/MM/dd"形式にフォーマット 148 const holidayDate = Utilities.formatDate(holiday.getStartTime(), Session.getScriptTimeZone(), "yyyy/MM/dd"); 149 // 祝日の日付を配列に追加 150 holidayDates.push(holidayDate); 151 } 152 153 return holidayDates; // 祝日の日付を含む配列を返す 154} 155 156function isHoliday(dateToCheck) { 157 const holidays = getHolidays(); // 祝日のリストを取得 158 159 // 指定された日付が祝日のリストに含まれているかどうかを確認 160 const formattedDateToCheck = Utilities.formatDate(dateToCheck, Session.getScriptTimeZone(), "yyyy/MM/dd"); 161 return holidays.includes(formattedDateToCheck); 162} 163 164// 指定された日付の前の平日(土日を除く前の日)を取得する関数 165function getPreviousWeekday(triggerDate) { 166 const previousDate = new Date(triggerDate); 167 168 do { 169 previousDate.setDate(previousDate.getDate() - 1); 170 } while (!isWeekday(previousDate) || isHoliday(previousDate)); 171 172 return previousDate; 173} 174 175

試したこと・調べたこと

上記の詳細・結果

祝日の条件分岐のコードを追加いたしました。
その際にソースコード変更したため当日実行がされなくなってしまいました。

また以前実行したものを再実行してしまうようになってしまいました。
↓こちらのコードで対応しています
const reservationDate = new Date(triggerDate);
Logger.log("トリガー日: " + reservationDate.toLocaleString("ja-JP"));

// 実行日がトリガー日の前営業日より前の日付やトリガー日より後の日付には通知しない const prevWeekday = getPreviousWeekday(today); Logger.log("前営業日: " + prevWeekday.toLocaleString("ja-JP")); if (today < prevWeekday || today >= reservationDate) { continue; } // 通知トリガーが実行日の4日前より未来の場合は通知しない const fourDaysBeforeTrigger = new Date(reservationDate); fourDaysBeforeTrigger.setDate(reservationDate.getDate() - 4); Logger.log("通知トリガーの4日前: " + fourDaysBeforeTrigger.toLocaleString("ja-JP")); if (today < fourDaysBeforeTrigger) { continue; }

補足

Apps Script

コメントを投稿

0 コメント