Для удобства поиска и понимания кода я разбил скрипт следующие блоки:
Global
// Telegram
const botToken = 'token'
const telegramUrl = "https://api.telegram.org/bot" + botToken + "/";
const googleUrl = "https://script.google.com/macros/s/symbols/exec";
// Google sheet
const ss = SpreadsheetApp.getActiveSpreadsheet()
const wsDb = ss.getSheetByName("DB")
const wsDebug = ss.getSheetByName("Debug")
const wsUsers = ss.getSheetByName("Users")
// Parametes
const LESSDAYS = 10 // За сколько дней ДО предпупреждать
const QUARTER = 90
const ADMIN_ID = <numbers>
Sheet main code
// Получение всего массива с датами и данными
function getAllData() {
const dbArr = wsDb.getDataRange().getValues() // весь массив с листа данных с датами и отчетами
const dbArrWithDates = dbArr.map( row => [row[0].toLocaleString().split(',')[0], row[1]]) // приводим его к читаемому виду
return dbArrWithDates;
}
// Получение даты для сравнения с датами в массиве
function getLessDays(){
const today = new Date() // сегодня
today.setDate(today.getDate() + LESSDAYS) // сдвиг на LESSDAYS
const resultDays = today.toLocaleString().split(',')[0] // дата в текст и читаемый вид для дальнейшего сравнения с getAllData
return resultDays;
}
// фильтрация общего массива на основании сравнения дат
function filteredDaysArr(){
const fullArr = getAllData() // весь массив
const compareDays = getLessDays() // дата для сравнения
const filteredArr = fullArr.filter(row => row[0] == compareDays) // фильтр всего массива по дате
return filteredArr
}
// Фильтрованный массив с датами в текст
function filteredArrToText(){
const filteredArr = filteredDaysArr(); // фильтрованный массив
const beautyArr = filteredArr.map(row =>[row[0]+" : " +row[1]]) // "причесанный" фильтрованный массив
const textFromArr = beautyArr.join('\n') // массив в текст с разделителем новой строки для отправки в телеграм
return textFromArr
}
// Для ежедневного триггера - проверка на наличие отправки
function checkerToSend(){
const text = filteredArrToText() // что сегодня рассылать - текст из фильтрованного массива
if(text.length !== 0){ // если длина текста не равна 0 - т.е. там есть что отправлять
const userArr = wsUsers.getDataRange().getValues() // получаю массив с пользовательскими id - кому идет рассылка
for(let elem of userArr){ // для каждого элемента массива с пользовательскими id
let messageText = `📨 Через ${LESSDAYS} дней срок подачи:\n`
sendMessage(elem, (messageText + text)) // отправка сообшения
}
}
}
Telegram
// Установка вебХука в телеграме
function setWebHook() { //выполняется единожды - установить вебХук
const url = telegramUrl+"setWebhook?url="+googleUrl;
const response = UrlFetchApp.fetch(url).getContentText();
const textResponse = JSON.parse(response);
console.log(textResponse)
}
// Удаление вебХука в телеграме
function deleteWebHook() { //выполняется единожды - удалить установленный выше вебХук
const url = telegramUrl+"deleteWebhook?url="+googleUrl;
const response = UrlFetchApp.fetch(url).getContentText();
const textResponse = JSON.parse(response);
console.log(textResponse)
}
// основная функция, которая обрабатывает входящие данные от телеграма
function doPost(e){
const main = JSON.parse(e.postData.contents); // получаем данные из телеграм бота
// вытаскиваем все данные из contents
const chatId = main.message.chat.id;
const firstName = main.message.chat.first_name;
const lastName = main.message.chat.last_name;
// const messageDate = main.message.date;
const messageText = main.message.text;
const arrayText = messageText.split(" "); // массив для последующей обработки команд
const detailsArray = [chatId, firstName, lastName, messageText, arrayText]; //собираем все что выше массив
const objToTransfer = Object.assign({}, detailsArray); // делаем из массива объект для передачи
analyseDetails(objToTransfer); //вызываем функцию для дальнейшей обработки того, что пришло - см Main code
}
Telegram main code
function analyseDetails(objReceived){ // анализ того, что пришло со стороны телеграма
const receivedCommand = objReceived[4][0].toLowerCase(); // "4": ["/list", "", "" и тд]
switch(receivedCommand){ //если пришла команда
case '/start':
sendStartMessage(objReceived);
break;
case '/help':
sendStartMessage(objReceived);
break;
case '/join':
setNewUser(objReceived);
break;
case '/list':
sendList(objReceived);
break;
default: // если пришло что-то отличное от команды
onModer(objReceived);
break;
}
}
function sendStartMessage(obj){
const userId = obj[0]; //Юзер id
const startMessage = `🤖 Привет! 🤖\n\n В своей базе я храню данные по срокам предоставления налоговых и бухгалтерских отчетов и деклараций. За ${LESSDAYS} дней до окончания срока я высылаю уведомление об этом.\n\n Чтобы я смог присылать такие уведомления Вам, отправьте команду /join\n\n Чтобы получить список деклараций и сроков их подачи в ближайший квартал, отправьте команду /list\n\n Если Вам необходимо добавить в базу недостающие сроки подачи деклараций, отправьте мне сообщение в виде "Дата: Декларация" и я передам его на модерацию`
sendMessage(userId, startMessage);
}
function setNewUser(obj){
const userId = obj[0]; //Юзер id
const userArr = wsUsers.getDataRange().getValues() // получаю массив массивов c пользовательскими id
const flatUserArr = userArr.flat() // делаю его обычным массивом для последующего indexOf
const userIsHere = flatUserArr.indexOf(userId) // делаю проверку наличия записи пользовательского ID
if(userIsHere !== -1){ // если такой пользователь уже есть
sendMessage(userId, "Пользователь уже есть в моей базе 🧐")
} else { // добавляю нового пользователя
wsUsers.appendRow([userId]) // appendRow - каждая ячейка это массив
sendMessage(userId, "Пользователь был успешно добавлен.\nВ ближайшее время ждите рассылку!")
}
}
// для выполнения /list - список подаваемых деклараций на ближайшие QUARTER дней
function getQuarterList(){
const today = new Date() // сегодня
const quarter = new Date()
quarter.setDate(today.getDate() + QUARTER) // сегодня + QUARTER дней
const allArr = wsDb.getDataRange().getValues() // массив со всеми датами и декларациями
const filteredArr = allArr.filter(row => (new Date(row[0])) > today && (new Date(row[0])) < quarter) // выбираем записи которые больше чем сегодня и меньше чем через QUARTER дней
const beautyArr = filteredArr.map(row => [(row[0].toLocaleString().split(',')[0]) + " : " + row[1]]) // причесываем для последующей конвертации в текст
const arrToText = beautyArr.join('\n')
return arrToText
}
// послать список подаваемых деклараций на ближайшие QUARTER дней
function sendList(obj){
const userId = obj[0]; //Юзер id
const text = getQuarterList() // данные к подаче на ближайшие QUARTER дней
sendMessage(userId, text);
}
// если пришло что-то отличное от команды - отправить администратору бота
function onModer(obj){
const userId = obj[0]
const userName = obj[1]
const userSurname = obj[2]
const userMessage = obj[3]
const text = `Пользователь ${userName} ${userSurname} с ID ${userId} послал на модерацию сообщение: ${userMessage}`
sendMessage(ADMIN_ID, text)
}
sendMessage
// базовая функция для отправки сообщения в телеграм с "сервера"
function sendMessage(chatid, chatText) {
const chatId = chatid;
const text = chatText;
const payload = {
"method": "sendMessage",
"chat_id": String(chatId),
"text": text,
"parse_mode": 'HTML',
"disable_web_page_preview": true
};
const data = {
"method": "post",
"payload": payload
};
UrlFetchApp.fetch(telegramUrl, data);
}