Google Apps Script — ИИ-помощник нейросети Аливия для тех, кто автоматизирует Google Таблицы, Документы, Формы и Gmail. Он пишет скрипт с комментариями и объясняет, как его установить, выдать доступы и поставить триггер по времени или при изменении. Укажите, где работает скрипт, что автоматизировать, какой нужен триггер и структуру листа — ИИ подготовит код.
Работает онлайнРусский и другие языкиТест бесплатно, без регистрацииБез VPNДоступ 24/7Голосовой ввод и файлы
Зарегистрируйтесь и подтвердите почту — начислим ещё 10 000 символов на 7 дней.ЗарегистрироватьсяОнлайн
Поиск инструментов
Весь каталог →Отдельной страницы под это нет, но Аливия справится в чате на этой странице.
Популярные инструменты для программистов
Программистам · ИИ-инструмент нейросети Аливия
Конструктор скриптов Google Apps Script
Выберите, где работает скрипт и когда запускается, опишите задачу — бот напишет код и объяснит установку.
Ещё настройки
Запрос подставится в поле чата — его можно поправить перед отправкой.
/**
* Отправляет письмо менеджеру при новой строке из формы.
* Читает адрес менеджера из листа «Настройки», ячейка B1.
* Обрабатывает лист «Заявки» и не повторяет отправку для уже отмеченных строк.
*/
function processFormSubmit(e) {
// Проверяем, что событие пришло от отправки формы
if (!e || !e.range) {
throw new Error('Функция должна запускаться триггером отправки формы.');
}
const ss = SpreadsheetApp.getActiveSpreadsheet();
// Листы из задачи — не переименовывать
const заявкиSheet = ss.getSheetByName('Заявки');
const настройкиSheet = ss.getSheetByName('Настройки');
if (!заявкиSheet) {
throw new Error('Не найден лист «Заявки».');
}
if (!настройкиSheet) {
throw new Error('Не найден лист «Настройки».');
}
// Читаем e-mail менеджера из B1
const managerEmail = String(настройкиSheet.getRange('B1').getValue()).trim();
if (!managerEmail) {
throw new Error('В ячейке B1 листа «Настройки» не указан e-mail менеджера.');
}
// Определяем строку, которую добавила форма
const row = e.range.getRow();
// Если это строка заголовков или выше — ничего не делаем
if (row < 2) {
return;
}
// Читаем всю строку целиком: A:E
const rowValues = заявкиSheet.getRange(row, 1, 1, 5).getValues()[0];
const timestamp = rowValues[0]; // A — отметка времени
const clientName = rowValues[1]; // B — имя
const phone = rowValues[2]; // C — телефон
const comment = rowValues[3]; // D — комментарий
const mailStatus = rowValues[4]; // E — статус письма
// Защита от повторной обработки уже отправленных строк
if (String(mailStatus).toLowerCase() === 'отправлено') {
return;
}
// Формируем тему и текст письма
const subject = 'Новая заявка из формы';
const body =
'Поступила новая заявка из формы.\n\n' +
'Дата и время: ' + timestamp + '\n' +
'Имя: ' + clientName + '\n' +
'Телефон: ' + phone + '\n' +
'Комментарий: ' + comment + '\n\n' +
'Строка в таблице: ' + row;
// Отправляем письмо менеджеру
GmailApp.sendEmail(managerEmail, subject, body);
// Отмечаем строку как обработанную
заявкиSheet.getRange(row, 5).setValue('отправлено');
}
/**
* Создаёт устанавливаемый триггер на отправку формы для текущей таблицы.
* Запускать вручную один раз.
*/
function createFormSubmitTrigger() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
// Удаляем старые триггеры с этой же функцией, чтобы не создавать дубли
const triggers = ScriptApp.getProjectTriggers();
for (let i = 0; i < triggers.length; i++) {
const trigger = triggers[i];
if (trigger.getHandlerFunction() === 'processFormSubmit') {
ScriptApp.deleteTrigger(trigger);
}
}
// Создаём триггер для таблицы
ScriptApp.newTrigger('processFormSubmit')
.forSpreadsheet(ss)
.onFormSubmit()
.create();
}
/**
* Проверочная функция для первого запуска и выдачи доступов.
* Запускать вручную один раз, затем можно удалить или оставить.
*/
function testPermissions() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
// Просто читаем активную таблицу, чтобы запросить доступы
const sheetName = ss.getName();
Logger.log('Текущая таблица: ' + sheetName);
}Как установить
- Откройте нужную Google Таблицу.
- Перейдите в «Расширения → Apps Script».
- Вставьте код целиком в файл скрипта, заменив шаблонный код, если он есть.
- Нажмите Сохранить.
- Сначала запустите вручную функцию
testPermissionsилиcreateFormSubmitTrigger:- выберите функцию в списке,
- нажмите ▶ Запуск,
- выдайте доступы.
- Если появится предупреждение о непроверенном приложении, это значит, что скрипт ещё не прошёл проверку Google. Для личного использования обычно нужно нажать «Дополнительные настройки» → «Перейти к проекту (небезопасно)» и подтвердить доступ.
- После этого вручную запустите функцию
createFormSubmitTrigger— она создаст устанавливаемый триггер черезScriptApp.newTrigger(...).forSpreadsheet(...).onFormSubmit(). - Также можно поставить триггер вручную через интерфейс:
- «Триггеры»
- «Добавить триггер»
- функция:
processFormSubmit - источник события: из таблицы
- тип события: при отправке формы
- Проверьте работу на копии таблицы перед использованием в бою.
Что важно учесть
- Простые триггеры здесь не подходят, поэтому используется именно устанавливаемый триггер.
- Письмо отправляется через
GmailApp.sendEmail(). - Защита от повторной отправки сделана через столбец E: если там уже стоит «отправлено», строка пропускается.
- Скрипт читает и обрабатывает данные пакетно через
getRange(...).getValues(). Отметка статуса в одной ячейке ставится после отправки письма. - Не отправляйте массовые письма без теста: сначала проверьте на одной тестовой заявке.
- Если у вас большой поток заявок, учитывайте квоты Gmail и Apps Script.
Если нужно, я могу сразу адаптировать этот же скрипт под вариант, где статус письма записывается в отдельный столбец с датой отправки вместо слова «отправлено».
// Google Apps Script для Google Таблиц
// Задача: каждый день утром проверять сроки договоров и подсвечивать строки:
// меньше 14 дней — красным, меньше 30 дней — жёлтым.
// Лист: "Договоры", заголовки в строке 1, данные со 2 строки.
// Создаёт ежедневный триггер на 8–9 утра
function createDailyTrigger() {
// Удаляем старые триггеры для этой функции, чтобы не плодить дубликаты
const triggers = ScriptApp.getProjectTriggers();
for (let i = 0; i < triggers.length; i++) {
if (triggers[i].getHandlerFunction() === 'checkContractsDeadline') {
ScriptApp.deleteTrigger(triggers[i]);
}
}
// Создаём новый триггер: каждый день, примерно в 8–9 утра
ScriptApp.newTrigger('checkContractsDeadline')
.timeBased()
.everyDays(1)
.atHour(8) // запуск в часовой интервал 8–9
.create();
}
// Проверяет даты окончания договоров и красит строки
function checkContractsDeadline() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Договоры'); // имя листа из задачи
if (!sheet) {
throw new Error('Лист "Договоры" не найден.');
}
const lastRow = sheet.getLastRow();
const lastColumn = 3; // A:C по структуре задачи
// Если нет данных кроме заголовка — ничего не делаем
if (lastRow < 2) {
return;
}
const range = sheet.getRange(2, 1, lastRow - 1, lastColumn);
const values = range.getValues();
// Подготавливаем массив цветов для всей таблицы разом
const backgrounds = [];
const today = new Date();
today.setHours(0, 0, 0, 0);
for (let i = 0; i < values.length; i++) {
const row = values[i];
const endDateValue = row[2]; // C — дата окончания
let color = null;
if (endDateValue instanceof Date && !isNaN(endDateValue)) {
const endDate = new Date(endDateValue);
endDate.setHours(0, 0, 0, 0);
const diffMs = endDate.getTime() - today.getTime();
const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
if (diffDays < 14) {
color = '#f4cccc'; // красный
} else if (diffDays < 30) {
color = '#fff2cc'; // жёлтый
}
}
// Красим всю строку A:C
backgrounds.push([color, color, color]);
}
// Одним вызовом применяем форматирование ко всему диапазону
range.setBackgrounds(backgrounds);
}Как установить:
- Откройте таблицу Google Sheets.
- Меню: Расширения → Apps Script.
- Вставьте код в файл
Code.gsвместо шаблона. - Нажмите Сохранить.
- Запустите вручную функцию
createDailyTrigger:- выберите её в списке функций;
- нажмите Выполнить.
- При первом запуске появится запрос доступа:
- выберите аккаунт;
- нажмите Разрешить;
- если увидите предупреждение о непроверенном приложении, это стандартное окно Google для скриптов без публикации. Нужно нажать Дополнительно → Перейти к [название проекта] → Разрешить.
- После этого откройте слева раздел Триггеры → Добавить триггер:
- функция:
checkContractsDeadline; - источник события: По времени;
- тип триггера: Таймер дня;
- время: 8–9 утра.
- функция:
Важно:
- Скрипт рассчитан на таблицу с листом «Договоры» и датой окончания в колонке C.
- Перед запуском проверьте на копии таблицы.
- Если данных много, помните про квоты Apps Script; здесь чтение и запись идут пакетно через
getValues()иsetBackgrounds(), без обработки по ячейке. - Не добавляйте массовую рассылку писем без теста.
Если нужен вариант, который ещё и пишет статус в отдельный столбец или отправляет уведомление на почту, я добавлю это в том же стиле.
// Google Apps Script для Google Таблиц
// Сценарий: при ручном изменении на листе "Задачи"
// Если в столбце F поставить "Готово" — записать текущую дату в G
// Если статус в F очистили — очистить дату в G
// Скрипт реагирует только на нужный лист и только на изменения в столбце F
function handleTaskStatusEdit(e) {
// Проверяем, что событие вообще пришло
if (!e || !e.range) return;
// Получаем лист, где было изменение
const sheet = e.range.getSheet();
// Срабатываем только на листе "Задачи"
if (sheet.getName() !== 'Задачи') return;
// Столбец F = 6
const editedColumn = e.range.getColumn();
// Нас интересует только столбец F
if (editedColumn !== 6) return;
// Не обрабатываем множественную вставку диапазона, только одиночную ячейку
if (e.range.getNumRows() !== 1 || e.range.getNumColumns() !== 1) return;
// Берём новое значение из события
const newValue = e.value;
// Номер строки, где произошла правка
const row = e.range.getRow();
// Диапазон для даты готовности в столбце G = 7
const dateCell = sheet.getRange(row, 7);
// Если статус стал "Готово", ставим текущую дату
if (newValue === 'Готово') {
dateCell.setValue(new Date());
return;
}
// Если статус очистили, очищаем дату
if (newValue === undefined || newValue === '') {
dateCell.clearContent();
return;
}
}Как установить
- Откройте Google Таблицу.
- Перейдите в Расширения → Apps Script.
- Вставьте код в файл
Code.gs. - Нажмите Сохранить.
- В редакторе Apps Script откройте Триггеры.
- Нажмите Добавить триггер.
- Выберите функцию
handleTaskStatusEdit. - Источник события: Из таблицы.
- Тип события: При изменении.
Если нужен именноe.rangeдля реакции на правку ячеек, в Apps Script обычно используют устанавливаемый триггер при редактировании. Для него выберите тип события При редактировании. - Сохраните триггер и выдайте доступы при первом запуске.
Почему здесь нужен устанавливаемый триггер
- Для обычного
onEdit(e)не требуется ручная установка, но он имеет ограничения. - Если в будущем потребуется доступ к почте, другим файлам или внешним сервисам, простой триггер не сможет это делать без авторизации.
- Устанавливаемый триггер запускается с правами пользователя и подходит для более сложных действий.
- Также у простого триггера есть ограничение по времени выполнения: около 30 секунд.
Что означает предупреждение о непроверенном приложении
Если при первом запуске появится окно с предупреждением о непроверенном приложении:
- это стандартное уведомление Google,
- оно появляется, когда скрипт ещё не прошёл проверку Google,
- нужно нажать Дополнительные сведения → Перейти к [название проекта],
- затем подтвердить доступы.
Важные замечания
- Скрипт настроен только на лист «Задачи».
- Он реагирует только на изменения в столбце F.
- Если в одной ячейке F поставить «Готово», в G проставится текущая дата.
- Если значение в F очистить, дата в G очистится.
- Проверяйте скрипт на копии таблицы перед работой в боевом файле.
Если нужно, я могу сразу сделать версию именно для простого триггера onEdit(e) без установки триггера.
/**
* Google Apps Script для Gmail
* Задача: раз в час находить письма с ярлыком «Счета»,
* сохранять вложения PDF в папку на Google Диске «Счета 2026»
* и снимать ярлык с уже обработанных писем.
*
* Важно:
* - Используются только существующие сервисы Apps Script: GmailApp, DriveApp, ScriptApp.
* - Нужны права доступа к Gmail и Google Диску.
* - Перед запуском проверьте на копии данных.
*/
/**
* Создаёт часовой триггер вручную из кода.
* Запускать один раз вручную.
*/
function createHourlyTrigger() {
// Удаляем старые триггеры этой же функции, чтобы не было дублей.
const triggers = ScriptApp.getProjectTriggers();
// Перебираем все триггеры проекта.
for (let i = 0; i < triggers.length; i++) {
// Если триггер уже на нужную функцию, удаляем его.
if (triggers[i].getHandlerFunction() === 'processInvoicesByLabel') {
ScriptApp.deleteTrigger(triggers[i]);
}
}
// Создаём новый триггер: каждый час.
ScriptApp.newTrigger('processInvoicesByLabel')
.timeBased()
.everyHours(1)
.create();
}
/**
* Основная функция обработки писем.
* Ищет письма с ярлыком «Счета», сохраняет PDF-вложения
* в папку «Счета 2026» и снимает ярлык после успешной обработки.
*/
function processInvoicesByLabel() {
// Название ярлыка из задачи.
const labelName = 'Счета';
// Название папки из задачи.
const folderName = 'Счета 2026';
// Получаем ярлык Gmail.
const label = GmailApp.getUserLabelByName(labelName);
// Если ярлык не найден, прекращаем выполнение.
if (!label) {
throw new Error('Не найден ярлык Gmail: ' + labelName);
}
// Получаем письма с этим ярлыком.
const threads = GmailApp.search('label:' + labelName);
// Находим или создаём папку на Диске.
let folder = getOrCreateFolderByName_(folderName);
// Обрабатываем все найденные цепочки писем.
for (let i = 0; i < threads.length; i++) {
// Берём все сообщения в цепочке.
const messages = threads[i].getMessages();
// Флаг успешной обработки всей цепочки.
let threadProcessed = false;
// Обрабатываем сообщения внутри цепочки.
for (let j = 0; j < messages.length; j++) {
// Получаем вложения письма.
const attachments = messages[j].getAttachments();
// Флаг: есть ли PDF во вложениях.
let hasPdf = false;
// Проверяем все вложения.
for (let k = 0; k < attachments.length; k++) {
// Проверяем MIME-тип PDF.
if (attachments[k].getContentType() === 'application/pdf') {
hasPdf = true;
// Формируем имя файла.
const fileName = makeSafeFileName_(
messages[j].getDate(),
attachments[k].getName(),
threads[i].getId()
);
// Сохраняем PDF в папку Google Диска.
folder.createFile(attachments[k].copyBlob().setName(fileName));
// Помечаем цепочку как обработанную.
threadProcessed = true;
}
}
// Если у письма не было PDF, ничего не делаем.
if (!hasPdf) {
continue;
}
}
// Если хотя бы одно PDF сохранено, снимаем ярлык.
if (threadProcessed) {
threads[i].removeLabel(label);
}
}
}
/**
* Возвращает существующую папку по имени или создаёт новую.
* @param {string} folderName Имя папки.
* @returns {GoogleAppsScript.Drive.Folder} Папка Google Диска.
*/
function getOrCreateFolderByName_(folderName) {
// Ищем папку по имени.
const folders = DriveApp.getFoldersByName(folderName);
// Если папка уже есть, возвращаем первую найденную.
if (folders.hasNext()) {
return folders.next();
}
// Иначе создаём новую папку.
return DriveApp.createFolder(folderName);
}
/**
* Делает безопасное имя файла.
* @param {Date} date Дата письма.
* @param {string} originalName Оригинальное имя вложения.
* @param {string} threadId ID цепочки письма.
* @returns {string} Безопасное имя файла.
*/
function makeSafeFileName_(date, originalName, threadId) {
// Форматируем дату вручную.
const yyyy = date.getFullYear();
const mm = String(date.getMonth() + 1).padStart(2, '0');
const dd = String(date.getDate()).padStart(2, '0');
const hh = String(date.getHours()).padStart(2, '0');
const min = String(date.getMinutes()).padStart(2, '0');
// Берём исходное имя или задаём запасное.
const baseName = originalName ? originalName : 'invoice.pdf';
// Очищаем имя от недопустимых символов.
const cleaned = baseName.replace(/[\\\/:*?"<>|]/g, '_');
// Возвращаем итоговое имя файла.
return yyyy + '-' + mm + '-' + dd + '_' + hh + '-' + min + '_' + threadId + '_' + cleaned;
}
/**
* Разовая ручная установка триггера через интерфейс:
* «Триггеры» → «Добавить триггер».
*
* В интерфейсе нужно выбрать:
* - Функция: processInvoicesByLabel
* - Источник события: По времени
* - Тип триггера: Таймер часов
* - Интервал: Каждый час
*
* Эту функцию запускать не нужно, она дана как инструкция в коде.
*/
function triggerSetupGuide() {
// Пустая служебная функция.
// Нужна только как напоминание, что триггер можно создать вручную через интерфейс.
}Как установить
- Откройте нужный Google-аккаунт и перейдите в таблицу/документ с проектом.
- Нажмите «Расширения → Apps Script».
- В редакторе удалите шаблонный код и вставьте скрипт целиком.
- Нажмите Сохранить.
- Запустите вручную функцию
createHourlyTrigger(). - При первом запуске Google попросит доступы:
- к Gmail — чтобы читать письма и снимать ярлык;
- к Google Диску — чтобы создавать папку и сохранять файлы.
- Если появится предупреждение «Это приложение не проверено», это означает, что скрипт ещё не проходил проверку Google. Для собственного проекта обычно можно открыть «Дополнительно» → «Перейти к проекту» и подтвердить доступ.
- После этого в редакторе можно также поставить триггер вручную: «Триггеры» → «Добавить триггер».
- Функция:
processInvoicesByLabel - Источник события: По времени
- Тип: Каждый час
- Функция:
Что делает защита от повторного выполнения
- Скрипт ищет письма с ярлыком «Счета».
- После успешного сохранения PDF из цепочки он снимает ярлык.
- Поэтому при следующем часовом запуске уже обработанные письма не попадут в обработку повторно.
Важно
- Проверьте скрипт на копии почты и Диска перед рабочим запуском.
- Не запускайте массовую обработку без теста.
- Если в письме несколько PDF, все они будут сохранены.
- Если ярлык есть, но PDF-вложений нет, ярлык не снимется.
Если хотите, я могу сразу сделать версию с журналом обработанных писем в отдельном листе или с поиском только непрочитанных писем.
Причина простая: GmailApp.sendEmail() нельзя вызывать из простого триггера onEdit(e).
Простой триггер работает с ограниченными правами, поэтому отправка письма блокируется. Для GmailApp нужен устанавливаемый триггер.
Еще момент: в вашем коде функция называется onEdit, а для устанавливаемого триггера лучше использовать другое имя, как вы и просили.
Исправленный код целиком:
function handleEditSendEmail(e) {
// Обрабатывает изменение статуса в столбце F на листе «Заявки»
const sheet = e.range.getSheet();
const editedColumn = e.range.getColumn();
const editedRow = e.range.getRow();
// Проверяем нужный лист и столбец F
if (sheet.getName() !== 'Заявки' || editedColumn !== 6) return;
// Берём новое значение из изменённой ячейки
const status = e.value || '';
// Если статус пустой, письмо не отправляем
if (!status) return;
// Отправляем письмо
GmailApp.sendEmail(
'boss@example.com', // [ЗАПОЛНИТЬ: адрес получателя, если нужен другой]
'Новый статус',
status
);
}Что было не так простыми словами:
onEdit(e)— это простой триггер.- Простой триггер не имеет права отправлять письма через
GmailApp. - Нужно поставить устанавливаемый триггер на эту функцию.
Шаги установки:
- Откройте Расширения → Apps Script.
- Вставьте код и сохраните проект.
- Запустите функцию
handleEditSendEmailвручную один раз, чтобы выдать доступы. - Если появится запрос разрешений — подтвердите их.
- Откройте Триггеры в Apps Script.
- Нажмите Добавить триггер.
- Выберите функцию:
handleEditSendEmail. - Источник события: Из таблицы.
- Тип события: При изменении.
- Сохраните триггер.
Важно:
- Проверьте сначала на копии таблицы.
- Не отправляйте массовые письма без теста.
e.valueв триггере есть только при редактировании одной ячейки; если вставляют диапазон сразу, значение может быть другим.- Для Gmail у аккаунта должны быть права на отправку писем; на некоторых аккаунтах Workspace администратор может ограничивать доступ.
Ниже — простыми словами, что делает ваш скрипт.
1) По функциям
function fillTemplate()
Что делает:
- Берёт текущий открытый Google Документ:
- DocumentApp.getActiveDocument()
- Получает его тело документа:
- doc.getBody()
- Но дальше переменная body никак не используется.
- Открывает таблицу по ID:
- SpreadsheetApp.openById('1AbC')
- Берёт лист с названием:
- 'Клиенты'
- Забирает все данные с этого листа:
- getDataRange().getValues()
- Пропускает первую строку:
- data.slice(1)
- Обычно это заголовки столбцов.
- Для каждой строки:
- делает копию текущего документа в Google Диске:
- DriveApp.getFileById(doc.getId()).makeCopy(r[0])
- Имя копии берётся из r[0]
- открывает эту копию как документ:
- DocumentApp.openById(copy.getId())
- заменяет в тексте шаблонные поля:
- {{ИМЯ}} → r[0]
- {{СУММА}} → r[1]
2) Когда он запускается и что произойдёт
Запуск:
- В коде нет триггера.
- Значит, функция fillTemplate() сама по себе не запускается автоматически.
- Она сработает только если:
- вы запустите её вручную из редактора Apps Script,
- или подключите к ней установимый триггер.
Что произойдёт при запуске:
- Скрипт прочитает все строки из листа 'Клиенты' в таблице с ID '1AbC'.
- Для каждой строки, начиная со второй:
- создаст отдельную копию текущего документа,
- назовёт копию значением из первого столбца строки,
- заменит в копии {{ИМЯ}} и {{СУММА}} на значения из строки.
3) Что опасного есть в скрипте
- Доступ к файлам:
- Да.
- Используются:
- DocumentApp.getActiveDocument()
- SpreadsheetApp.openById('1AbC')
- DriveApp.getFileById(doc.getId()).makeCopy(...)
- DocumentApp.openById(copy.getId())
- Это значит, что скрипт читает таблицу, берёт текущий документ и создаёт копии файлов на Диске.
- Отправка писем:
- Нет.
- GmailApp в коде не используется.
- Удаление данных:
- Нет.
- Удаляющих методов нет.
- Внешние запросы:
- Нет.
- UrlFetchApp и похожие сервисы не используются.
4) Проверка сервисов, классов и методов
В вашем коде используются корректные сервисы Apps Script:
- DocumentApp.getActiveDocument() — существует
- doc.getBody() — существует
- SpreadsheetApp.openById('1AbC') — существует
- getSheetByName('Клиенты') — существует
- getDataRange().getValues() — существует
- DriveApp.getFileById(doc.getId()) — существует
- makeCopy(r[0]) — существует
- DocumentApp.openById(copy.getId()) — существует
- replaceText('{{ИМЯ}}', r[0]) — существует
- replaceText('{{СУММА}}', r[1]) — существует
По аргументам:
- openById принимает строку ID — у вас так и есть.
- getSheetByName принимает имя листа — у вас так и есть.
- makeCopy принимает имя новой копии — у вас так и есть.
- replaceText принимает шаблон и строку замены — у вас используется корректно, но значения лучше приводить к строке, если есть риск, что там не текст.
5) Важные замечания
- Переменная body:
- объявлена, но не используется.
- data содержит весь лист:
- если в листе много строк, скрипт создаст много копий документа.
- Если r[0] пустой:
- имя копии может получиться пустым или неудобным.
- Если в r[1] число:
- replaceText обычно ожидает строку, лучше явно преобразовать:
- String(r[1])
6) Простое объяснение в одну фразу
Этот скрипт берёт строки из таблицы 'Клиенты', делает по одной копии текущего документа на каждую строку и подставляет в копии имя и сумму из таблицы.
7) Что в нём не хватает для запуска по триггеру
Сейчас триггера нет. Если нужен автоматический запуск, нужно отдельно добавить установимый триггер на функцию fillTemplate.
Если хотите, я могу сразу переписать этот же скрипт в более надёжном виде: с проверкой пустых строк, преобразованием значений к строке и понятными комментариями.Ответы получены 19.10.2026 в этом чате и приведены без правок. Выделено то, чего не было в запросе.
Что такое Google Apps Script и как нейросеть пишет скрипты
Google Apps Script — это платформа Google для автоматизации Таблиц, Документов, Форм, Gmail, Календаря и Диска: скрипты пишутся на JavaScript и выполняются на серверах Google, без установки программ. Простыми словами, это аналог макросов VBA, только для сервисов Google. Скрипт может заполнять ячейки, отправлять письма, создавать документы по шаблону и запускаться сам по расписанию.
Конструктор запроса под чатом собирает исходные данные: где работает скрипт (Таблицы, Документы, Формы, Gmail), что нужно автоматизировать, какой триггер — вручную, по времени, при изменении, при отправке формы — и структуру листа: названия листов, столбцы, с какой строки начинаются данные. Нейросеть пишет код с комментариями на русском и пошаговую инструкцию по установке.
Если вы работаете в Excel, а не в Google Таблицах, вам нужны макросы VBA — у них другой язык и другие возможности. А готовую структуру таблицы для учёта клиентов, склада или бюджета удобно сначала собрать в шаблоне учёта в Google Таблицах, а потом автоматизировать скриптом.
Что можно автоматизировать скриптом
- Таблицы: отметка времени при изменении, перенос строк между листами, архив отчётов, своё меню с кнопками, пользовательские функции для ячеек.
- Gmail: рассылка писем по списку из таблицы, напоминания о сроках, разбор входящих писем в таблицу.
- Формы: обработка ответов, уведомления ответственному, создание документа по каждому ответу.
- Документы и Диск: договоры и счета по шаблону с подстановкой данных из строки, сохранение в PDF, раскладка файлов по папкам.
- Внешние сервисы: запрос к API, например курсы валют или данные CRM, с записью результата на лист.
Триггеры: как заставить скрипт запускаться самому
Триггер — это событие, по которому скрипт запускается без нажатия кнопки. От выбора триггера зависит, что скрипту разрешено делать.
| Триггер | Когда срабатывает | Ограничения | Пример задачи |
|---|---|---|---|
| Простой onEdit(e) | Пользователь меняет ячейку | Не дольше 30 секунд, без сервисов, которым нужна авторизация (например, Gmail), не срабатывает на изменения из скрипта или API | Отметка времени при смене статуса |
| Простой onOpen(e) | Файл открыли на редактирование | Те же, что у onEdit | Своё меню в таблице |
| Устанавливаемый «При изменении» | Изменение ячейки, как у onEdit | Работает от имени автора, может отправлять письма | Уведомление на почту при новой заявке |
| Устанавливаемый «По времени» | По расписанию: каждый час, день, неделю | Общее время работы триггеров ограничено квотой | Ежедневные напоминания, архив отчётов |
| «При отправке формы» | Пришёл ответ в Google Форму | Нужна авторизация при установке | Документ по шаблону для каждого ответа |
Если скрипт в onEdit пытается отправить письмо и падает с ошибкой прав, причина почти всегда в простом триггере: нейросеть переименует функцию и объяснит, как поставить устанавливаемый триггер.
Как получить и установить скрипт
- Опишите в конструкторе задачу, сервис и триггер, перечислите листы и столбцы: «лист Заявки, A — дата, B — клиент, C — статус, данные со 2-й строки».
- Получите код и прочитайте комментарии: в них отмечено, какие имена листов и номера столбцов поменять под себя.
- В таблице откройте «Расширения» → «Apps Script», удалите пустую функцию и вставьте код, сохраните проект.
- Запустите функцию один раз вручную кнопкой «Выполнить» и подтвердите доступы: Google покажет, к каким данным скрипт просит доступ.
- Для запуска по расписанию откройте раздел «Триггеры» в редакторе, нажмите «Добавить триггер», выберите функцию, источник «По времени» и интервал.
- Проверьте результат на копии таблицы или на нескольких тестовых строках и только потом включайте на рабочих данных.
Готовый запрос: «Google Таблица, лист Задачи: A — задача, B — email ответственного, C — срок (дата), D — статус. Данные со 2-й строки. Напиши скрипт, который каждый день в 9 утра отправляет письмо ответственному, если до срока остался 1 день и статус не „Готово“. Добавь комментарии и инструкцию, как поставить триггер по времени».
Пример скрипта с разбором
Вот как выглядит ответ на запрос выше. Код читает лист целиком одним вызовом — так быстрее, чем обращаться к каждой ячейке.
function sendDeadlineReminders() {
const sheet = SpreadsheetApp.getActive().getSheetByName('Задачи');
const rows = sheet.getDataRange().getValues();
const today = new Date();
for (let i = 1; i < rows.length; i++) {
const [task, email, deadline, status] = rows[i];
if (status !== 'Готово' && deadline instanceof Date) {
const days = Math.ceil((deadline - today) / 86400000);
if (days === 1) {
MailApp.sendEmail(email, 'Завтра срок: ' + task,
'Срок задачи «' + task + '» наступает завтра.');
}
}
}
}Цикл начинается с 1, чтобы пропустить строку заголовков. Проверка deadline instanceof Date защищает от пустых и текстовых ячеек в столбце сроков. Функцию запускает триггер «По времени» — простой триггер здесь не подойдёт, потому что отправка почты требует авторизации.
Чем Apps Script отличается от макросов VBA
Задачи похожи, но среда другая. Макрос VBA живёт внутри файла Excel и выполняется на вашем компьютере, а скрипт Apps Script хранится в облаке Google и работает на серверах, даже когда таблица закрыта и компьютер выключен. Поэтому рассылки и отчёты по расписанию в Google Таблицах делаются проще: не нужно оставлять открытым Excel.
Обратная сторона — квоты и права. Скрипт выполняется от имени пользователя, который его запустил или поставил триггер, и видит только то, к чему этот пользователь дал доступ. Если таблица общая, договоритесь, кто владелец триггеров: при удалении его аккаунта или отзыве доступа автоматизация остановится.
Квоты и ограничения, о которых стоит знать
У Apps Script есть лимиты, и они разные для личных аккаунтов и Google Workspace. Для обычного аккаунта gmail.com одно выполнение скрипта длится не больше 6 минут, суммарное время работы триггеров — 90 минут в день, MailApp отправляет письма не более чем 100 получателям в день, а на один скрипт у пользователя может быть до 20 триггеров. Пользовательская функция в ячейке работает не дольше 30 секунд.
Не запускайте непроверенный скрипт на рабочей таблице и не давайте доступ к своему аккаунту скриптам из неизвестных источников. При первом запуске Google просит разрешения на чтение таблиц, отправку почты или доступ к Диску — читайте список и сверяйте с тем, что скрипт должен делать. Для массовой рассылки сначала отправьте письмо себе и проверьте текст и адресатов.
Как проверить, что скрипт работает правильно
- Откройте «Выполнения» в редакторе Apps Script: там видно, когда скрипт запускался, сколько работал и с какой ошибкой упал.
- Добавьте
console.logв ключевые места и посмотрите журнал при ручном запуске. - Проверьте краевые случаи: пустая строка, текст вместо даты, удалённый лист, повторный запуск в тот же день.
- Убедитесь, что скрипт не упирается в квоты: если строк тысячи, его стоит разбить на части или читать данные пакетами.
Apps Script построен на JavaScript, поэтому общие вопросы языка — массивы, даты, строки — можно разобрать в генераторе кода на JavaScript. Если задача решается без кода, попробуйте сначала формулы Google Таблиц: QUERY, FILTER и IMPORTRANGE закрывают многие сценарии. А где в интерфейсе найти нужную кнопку, подскажут инструкции «как сделать» для Excel и Word и Google Таблиц.
Аливия работает без регистрации и без VPN из России, принимает скриншоты таблицы и файлы CSV и Excel, чтобы понять структуру листа. Перед отправкой уберите из примеров реальные адреса и персональные данные клиентов. На бесплатном доступе есть дневной лимит запросов, у платных тарифов он больше.
Google Apps Script: частые вопросы
Как открыть Google Apps Script в таблице?
На каком языке пишут Google Apps Script?
Почему onEdit не отправляет письма?
Как запустить скрипт по расписанию?
Сколько писем в день может отправить Apps Script?
Сколько времени может работать скрипт?
Безопасно ли давать скрипту доступ к аккаунту?
Можно ли перевести макрос VBA в Apps Script?
Можно ли написать свою функцию для ячейки?
Что делать, если скрипт выдаёт ошибку?
Итог
Google Apps Script в Аливии — это готовый скрипт с комментариями для Таблиц, Документов, Форм и Gmail и инструкция по установке, доступам и триггеру. Нейросеть подбирает тип триггера под задачу и учитывает квоты Google. Перед запуском на рабочих данных проверьте скрипт на копии таблицы и посмотрите журнал выполнений.