Як автоматично створювати PDF-рахунки з Google Таблиці через Apps Script

9 хв читанняОновлено

Кейс для ФОП і фрилансерів: шаблон у Google Docs + Apps Script генерують персоналізований PDF-рахунок з кожного рядка таблиці й надсилають клієнту.

Поділитись:TelegramX

Коротка відповідь

Схема без сторонніх сервісів: створюєте шаблон рахунку в Google Docs з плейсхолдерами на кшталт {{Ім'я}} і {{Сума}}, а Apps Script для кожного рядка таблиці копіює шаблон, замінює плейсхолдери реальними даними через Body.replaceText(), конвертує копію в PDF через File.getAs('application/pdf') і зберігає чи одразу надсилає клієнту поштою. Весь ланцюжок — на безкоштовних вбудованих сервісах Google.

Навіщо це ФОП і фрилансерам

Ручне складання рахунку в шаблоні Word/Docs і збереження в PDF для кожного нового клієнта — це 5-10 хвилин рутини на рахунок. При 20-30 рахунках на місяць це вже кілька годин щомісяця на суто механічну роботу з копіювання даних без жодної творчої складової — ідеальний кандидат на автоматизацію навіть без бюджету на платні сервіси виставлення рахунків.

Крок 1 — Підготувати шаблон у Google Docs

Створіть звичайний Google Docs документ з дизайном рахунку, і замість реальних даних впишіть плейсхолдери у фігурних дужках:

Рахунок № {{Номер}}
Дата: {{Дата}}

Клієнт: {{Клієнт}}
Послуга: {{Послуга}}
Сума до сплати: {{Сума}} грн

Фігурні дужки — довільний вибір (можна й інший формат), головне — унікальний, легко впізнаваний текст, якого більше ніде в документі немає.

Крок 2 — Підготувати таблицю з даними

У Google Таблиці — один рядок на один рахунок, з колонками, що відповідають плейсхолдерам:

Номер Дата Клієнт Послуга Сума Email Статус
001 01.09.2026 ТОВ "Приклад" Консультація 5000 client@example.com (порожньо)

Колонка "Статус" — так само, як і в розсилці email (див. як автоматично надсилати email з Google Таблиць) — щоб скрипт не створював той самий рахунок двічі.

Крок 3 — Скрипт генерації

function generateInvoices() {
  const TEMPLATE_ID = 'ID_ШАБЛОНУ_З_URL_ДОКУМЕНТА';
  const FOLDER_ID = 'ID_ПАПКИ_ДЛЯ_ГОТОВИХ_РАХУНКІВ';

  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const data = sheet.getDataRange().getValues();
  const folder = DriveApp.getFolderById(FOLDER_ID);

  for (let i = 1; i < data.length; i++) {
    const [number, date, client, service, amount, email, status] = data[i];
    if (status === 'створено' || !number) continue;

    // 1. Скопіювати шаблон
    const templateFile = DriveApp.getFileById(TEMPLATE_ID);
    const copy = templateFile.makeCopy(`Рахунок №${number}`, folder);
    const doc = DocumentApp.openById(copy.getId());
    const body = doc.getBody();

    // 2. Замінити плейсхолдери реальними даними
    body.replaceText('{{Номер}}', number);
    body.replaceText('{{Дата}}', date);
    body.replaceText('{{Клієнт}}', client);
    body.replaceText('{{Послуга}}', service);
    body.replaceText('{{Сума}}', amount);
    doc.saveAndClose();

    // 3. Конвертувати в PDF
    const pdfBlob = DriveApp.getFileById(copy.getId()).getAs('application/pdf');
    const pdfFile = folder.createFile(pdfBlob).setName(`Рахунок №${number}.pdf`);

    // 4. Надіслати клієнту, якщо є email
    if (email) {
      MailApp.sendEmail(email, `Рахунок №${number}`, 'Додаємо рахунок у вкладенні.', {
        attachments: [pdfFile.getAs(MimeType.PDF)]
      });
    }

    // 5. Прибрати чернетку Google Docs — лишається тільки готовий PDF
    DriveApp.getFileById(copy.getId()).setTrashed(true);

    sheet.getRange(i + 1, 7).setValue('створено');
  }
}

Ключові API-методи тут — офіційні, з довідника Apps Script:

  • Body.replaceText(searchPattern, replacement) — заміна тексту за регулярним виразом, не буквальним збігом. Для звичайних плейсхолдерів на кшталт {{Сума}} це працює без додаткового екранування, але якщо у ваших даних трапляються спецсимволи regex (., *, +, (, )), їх варто екранувати перед підстановкою
  • File.getAs(contentType) — повертає вміст файлу у вигляді blob потрібного типу; для PDF — 'application/pdf'. Працює для будь-якого файлу на Диску, не тільки Google Docs

Крок 4 — Дозволи, які запросить Google

Перший запуск скрипта запросить авторизацію на:

  • Доступ до Google Таблиць (читання даних)
  • Доступ до Google Диска (копіювання шаблону, створення PDF) — саме getAs()/getBlob() на файлах Диска вимагають область доступу drive
  • Надсилання email від вашого імені (якщо використовуєте MailApp.sendEmail)

Крок 5 — Автоматичний запуск (тригер)

Так само, як і для розсилки листів — через Time-driven тригер (Тригери → Додати тригер → Time-driven), щоб скрипт сам перевіряв нові рядки за розкладом, без ручного натискання ▶.

Альтернатива для рахунків "по кнопці", а не за розкладом — власний пункт меню в самій таблиці:

function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('Рахунки')
    .addItem('Створити нові рахунки', 'generateInvoices')
    .addToUi();
}

Це додає пункт "Рахунки → Створити нові рахунки" у меню таблиці — зручно, коли рахунки створюються нерегулярно і краще контролювати момент запуску вручну.

Поширені помилки

Плейсхолдер не замінюється. Найчастіша причина — текст у документі "розбитий" автоформатуванням Google Docs на кілька фрагментів форматування (наприклад, частина слова виділена іншим кольором чи стилем), і replaceText() не бачить його як суцільний рядок. Рішення — набрати плейсхолдер заново одним стилем форматування, без правок посеред слова.

Дублікати рахунків при повторному запуску. Як і з email-розсилкою — без колонки-позначки "створено" скрипт при кожному запуску тригера обробляє всі рядки заново. Обов'язково записуйте статус одразу після генерації.

"You do not have permission to call getAs". Означає, що скрипт намагається конвертувати файл, до якого немає доступу — найчастіше плутанина між ID шаблону і ID вже готового PDF. Перевірте, що TEMPLATE_ID веде саме на Google Docs файл-шаблон, а не на щось інше.

Символи {{ }} трактуються як регулярний вираз, а не буквальний текст. Фігурні дужки самі по собі не спецсимволи regex, тому в базовому випадку проблем нема. Але якщо в даних таблиці (наприклад, у назві послуги) трапляється крапка, зірочка чи дужки — саме ці символи можуть зламати наступні виклики replaceText(), якщо їх випадково підставити як частину searchPattern. Підставляйте спецсимволи лише в replacement (другий аргумент), не в перший.

Коли варто перейти на щось складніше за Apps Script

Ця схема добре працює для одного власника таблиці, помірної кількості рахунків на місяць і простого шаблону без умовної логіки (наприклад, різні ставки ПДВ залежно від типу клієнта). Якщо потрібна командна робота кількох людей над одним потоком рахунків, інтеграція з бухгалтерським сервісом чи CRM, чи розгалужена логіка залежно від типу угоди — це вже точка, де варто подивитись на n8n, Zapier чи Make з готовими інтеграціями бухгалтерських сервісів: різницю в підходах розібрано в порівнянні n8n, Zapier і Make.

Часті питання

Чи можна створювати рахунки не в PDF, а одразу в Google Docs?

Так, кроки 1-2 (копіювання шаблону й заміна плейсхолдерів) дають готовий документ Google Docs сам по собі — конвертація в PDF (крок 3) потрібна тільки якщо вам важливий саме файл, який клієнт може відкрити без Google-акаунта.

Чи можна додати логотип чи печатку компанії в шаблон?

Так, зображення в шаблоні Google Docs копіюються разом з рештою документа при makeCopy() — жодних додаткових дій у скрипті для цього не потрібно, досить один раз вставити зображення в сам шаблон.

Що робити, якщо рахунків стає забагато для ручної перевірки перед відправкою?

Додайте проміжний крок: спочатку генеруйте PDF і зберігайте в папку без автоматичного надсилання (приберіть виклик MailApp.sendEmail з циклу), перевірте візуально кілька файлів, і лише тоді запускайте окрему функцію розсилки вже готових файлів з папки.

Чи спрацює цей скрипт, якщо в шаблоні є таблиці чи списки, а не тільки текст?

Так, Body.replaceText() проходить по всьому текстовому вмісту документа, включно з текстом усередині таблиць Google Docs — плейсхолдер у клітинці таблиці замінюється так само, як у звичайному абзаці.


Дата останньої перевірки актуальності: 18 серпня 2026 р. Сигнатури методів звірені з офіційним Apps Script Reference — Drive Service і Document Service.

Схожі статті