Shut up and give it to me for free
Что такое Google Apps Script и на чем он работает
- DocumentApp — для работы с Google Docs.
- GmailApp — для работы с Gmail.
- SlidesApp — для работы с Google Slides.
- SpreadsheetApp — для работы с Google Sheets.
- FormApp — для работы с Google Form.
Сразу к делу. Фишки Apps Script
Все наши внутренние команды имеют как минимум одну автоматизированную табличку. Например, для команд — это рентабельность по проекту с учетом трека времени, данных из Битрикса, подрядчиков и самого руководителя проекта.
Еще наш финотдел активно использует автоматизированные таблички: следят за расхождениями между затратами, за сроками выплат и актуальностью статусов по документам и т. д. Так 50–100 строчек кода ежедневно экономят нам по 2–3 часа на другие более приоритетные задачи.
Подробнее про API
/** Функция обращения к таск трекеру по API */
function taskTrackerAuth() {
const sourceUrl = 'https://your_taskTracker_url/rest/tempo-timesheets/4/worklogs/search';
const options = {
'headers': { 'Authorization': 'Basic *******************' },
'method': 'post',
'contentType': 'application/json',
'Accept': 'application/json',
/** Полезная нагрузка настраивается индивидуально, то что указано тут можно очистить */
'payload': JSON.stringify({'from': [],'to': [], 'worker': [], 'projectKey': [], 'taskKey': [], 'filterId': [] }),
}
const taskTrackerResponse = UrlFetchApp.fetch(sourceUrl, options);
const data = JSON.parse(taskTrackerResponse.getContentText());
//Вывод сообщения о получении данных
if (data.length > 0) {
SpreadsheetApp.getActiveSpreadsheet().toast('Данные Timesheets получены', '(V)_O_o_(V)', 2);
} else {
SpreadsheetApp.getActiveSpreadsheet().toast('Данные Timesheets не получены', '(V)_O_o_(V)', 2);
}
}
Пример работы с Apps Script
Создадим документ Google Sheets у себя на диске Google Drive.
Итак, создаю второй документ Google Sheets и заполняю его рандомными данными:
Во втором документе Данные.
Далее пишем этот код в редакторе кода первой таблицы.
Код получился длинным, так как я попытался расписать каждый шаг максимально подробно и добавил пару проверок. На самом деле весь этот блок можно сделать в несколько раз компактнее:
/** Функция получения данных */
function getData() {
/** Сокращение */
const ss = SpreadsheetApp.getActiveSpreadsheet();
/** ID документа с которого будем забирать данные */
const sheetId = '1AxL1WddtqlanF-WwkpF-2qTj3V1NCHc2xRzVLF7v3ho';
/** Имя листа с которого будем забирать данные */
const exportSheetName = 'Данные';
/** Имя листа на который будем вставлять данные */
let importSheetName = 'Импорт данных';
/** Проверка на корректность ID страницы */
try {
SpreadsheetApp.openById(sheetId);
} catch (e){
ss.toast('Ошибка в ID страницы', '(V)_O_o_(V)', 4);
}
/** Открываем таблицу с указанным идентификатором */
const openSheet = SpreadsheetApp.openById(sheetId);
/** Открываем лист с указанным именем */
const openList = openSheet.getSheetByName(exportSheetName);
/** Проверка на существование листа с которого забираем данные */
try {
openList.getDataRange().getValues();
} catch (e){
ss.toast('Экспорт: Страницы с таким именем не существует', '(V)_O_o_(V)', 4);
}
/** Забираем данные с листа */
const data = openList.getDataRange().getValues();
/** Небольшая проверка на существование данных */
if (Object.values(data) != 0) {
/** Выведем сообщение о получении данных */
ss.toast('Данные получены', '(V)_O_o_(V)', 4);
/** Если такой лист уже есть, то создадим другой*/
if (ss.getSheetByName(importSheetName) != 0) {
/** Зафиксируем текущее время */
let todayDate = new Date (Date.now());
/** Если лист с таким именем уже есть, то добавляем ему в название old + текущее время */
SpreadsheetApp.getActive().getSheetByName(importSheetName).setName(importSheetName + " old " + todayDate.toUTCString());
/** Создаем свежий лист */
ss.insertSheet().setName(importSheetName);
} else {
/** Создаем свежий лист если такого небыло до этого */
ss.insertSheet().setName(importSheetName);
}
/** Импортируем данные на страницу */
ss.getSheetByName(importSheetName).getRange(1, 1, data.length, data[0].length).setValues(data);
/** Выведем сообщение о вставке данных */
ss.toast('Данные вставлены на лист', '(V)_O_o_(V)', 4);
} else {
/** Выведем сообщение об отсутствии данных */
ss.toast('Эх.. А данных то нет', '(V)_O_o_(V)', 4);
};
}
/** Функция очистки листа */
function clearList() {
/** Сокращение */
const ss = SpreadsheetApp.getActiveSpreadsheet();
/** Имя листа, который будем очищать */
const clearListName = 'Импорт данных';
/** Выделим лист с которым будем работать */
const clearSheet = ss.getSheetByName(clearListName);
/** Подсчитаем количество всех строк на листе */
const maxRowsCount = clearSheet.getMaxRows();
/** Подсчитаем количество всех столбцов на листе */
const maxColumnsCount = clearSheet.getMaxColumns();
/** Очистим весь лист */
clearSheet.getRange(1, 1, maxRowsCount, maxColumnsCount).clear({ contentsOnly: true }); // Позволяет после очистки перезаписывать контент
/** Выведем сообщение об отсутствии данных */
ss.toast('Лист очищен', '(V)_O_o_(V)', 4)
};
/** Функция отображения выпадающего списка с кнопками в интерфейсе Google Sheets */
function onOpen() {
let ui = SpreadsheetApp.getUi();
ui.createMenu('Печеньки тут')
.addItem('Загрузить данные', 'getData')
.addItem('Очистить данные', 'clearList')
.addToUi();
}
- getData() — функция получения всех данных из другого документа.
- clearList() — функция очистки листа от любых данных, которые находятся в нем.
- onOpen() — функция вызова дополнительного меню в интерфейсе самой таблички.
const sheetId = '1AxL1WddtqlanF-WwkpF-2qTj3V1NCHc2xRzVLF7v3ho';
- Важно! Нужно вставить id страницы, с которой вы хотите забрать данные.
const exportSheetName = 'Данные';
const importSheetName = 'Импорт данных';
}
const clearListName = 'Импорт данных';
В коде я разместил проверки. Если вы где-нибудь допустите ошибку, то получите сообщение с пояснением, где именно ошибка.
- Данный код имитирует функцию IMPORTRANGE() в Google Sheets.
1. В редакторе выбираем функцию getData() и нажимаем выполнить:
- Загрузить данные.
Получаете данные с другого листа. Если лист пустой, то функция просто выдаст сообщение, что данных нет. - Очистить лист.
Стираете все данные с листа.
Если вдруг вы получили ошибку, то проверьте внимательно, правильно ли вы выполнили все шаги и не упустили ли что-то.
Пример очень простой и на его реализацию уйдет 5–10 минут со всеми настройками и отладками. Но по сути мы уже получили табличку, которой можно пользоваться нестандартно.
Почему Apps Script, а не обычные функции Google Sheets
Одна выгрузка данных за пару месяцев выглядит примерно вот так. Почти 46000 строк данных, которые надо полностью перебрать и сопоставить с данными из другой системы.
Поэтому симбиоз стандартных функций и немного скриптологии дают впечатляющие результаты. Но одно не отменяет другого: что-то удобнее сделать посредством кода, а что-то внутренними функциями. Так сказать, берем лучшее из обоих миров.
Пример архитектуры, которую мы выстроили с помощью Google Sheets
Благодаря такой системе мы можем получать и обрабатывать данные за полгода и более. Если вдруг где-то закралась ошибка, то она будет отображаться в таблице пользователя или буферной таблице. Согласитесь, ведь получается быстрее и эффективнее, когда ты точно знаешь, где ошибка, а не тратишь полдня на поиск разногласия.
Одна из сложностей, для которой есть решение
Таким образом у нас получается 40–50 дублей этой таблички, которые работают независимо друг от друга.
При обновлениях функциональности, по идее нам нужно брать ноги в руки, бегать по всем табличкам и вносить изменения вручную. Но тут нам на помощь приходят библиотеки! Библиотека в Apps Script выглядит как отдельный файл с кодом, который подключается к табличкам в меню редактирования кода. Из дополнительных плюсов этого решения — можно быть уверенным, что никто туда лишний раз не залезет и не наворошит там своими очумелыми ручками :)
У нас не раз были истории, когда приходит сотрудник и просит о помощи: «Хелп, ахтунг, алерт, у меня ничего не работает!». И ты с лицом лягушки Пепе бежишь смотреть, что же там произошло.
- Основной код лежит подальше от любопытных глаз и рук. Нельзя пофиксить то, что ты не видишь :)
- Изменения в главном файле применяются ко всем документам, к которым прикреплена эта библиотека.
- Становится легче определить ошибку кода или локальную ошибку.
Заключение
- Туториал от самого Google: https://developers.google.com/apps-script?hl=ru
- Описание методов Apps Script для Google Sheets: https://developers.google.com/apps-script/reference/spreadsheet?hl=ru