Ile czasu Twój zespół spędza co miesiąc na „eksportuj do PDF → zmień nazwę → wyślij mailem"? W firmach B2B generujących dziesiątki faktur, umów czy raportów tygodniowo, ta ręczna praca pochłania 5–10 godzin miesięcznie. Google Apps Script pozwala zredukować to do zera – jeden klik lub pełna automatyzacja bez ingerencji człowieka.

Koncepcja: szablon + dane = gotowy PDF

Cały mechanizm opiera się na prostym wzorcu:

  1. Szablon – Google Docs z placeholderami (np. {{NAZWA_FIRMY}}, {{KWOTA}}, {{DATA}}).
  2. Dane – wiersz w Google Sheets z konkretnymi wartościami dla każdego klienta/raportu.
  3. Skrypt – kopiuje szablon, podmienia placeholdery na dane, konwertuje do PDF i zapisuje na Dysku lub wysyła mailem.

To w zasadzie Mail Merge na sterydach – bez żadnych płatnych pluginów. Ten sam mechanizm możesz podpiąć pod formularze Google Forms, żeby PDF generował się automatycznie po każdym wypełnieniu ankiety.

Gotowy skrypt: generowanie PDF z szablonu

Poniższy kod iteruje po wierszach w Arkuszu, dla każdego generuje spersonalizowany dokument PDF i zapisuje go w wybranym folderze na Dysku:

function generatePDFReports() {
  const TEMPLATE_ID = 'ID_TWOJEGO_SZABLONU_DOCS';
  const OUTPUT_FOLDER_ID = 'ID_FOLDERU_NA_PDF';
  const SHEET_NAME = 'Dane';

  const sheet = SpreadsheetApp.getActiveSpreadsheet()
                  .getSheetByName(SHEET_NAME);
  const rows = sheet.getDataRange().getValues();
  const headers = rows[0];
  const outputFolder = DriveApp.getFolderById(OUTPUT_FOLDER_ID);

  for (let i = 1; i < rows.length; i++) {
    const row = rows[i];
    if (row[headers.indexOf('Status')] === 'Wygenerowano') continue;

    // Kopia szablonu
    const templateFile = DriveApp.getFileById(TEMPLATE_ID);
    const copy = templateFile.makeCopy(
      `Raport_${row[headers.indexOf('Firma')]}_${new Date().toISOString().slice(0,10)}`,
      outputFolder
    );
    const doc = DocumentApp.openById(copy.getId());
    const body = doc.getBody();

    // Podmiana placeholderów
    headers.forEach((header, idx) => {
      body.replaceText(`{{${header}}}`, String(row[idx]));
    });
    doc.saveAndClose();

    // Konwersja do PDF
    const pdfBlob = DriveApp.getFileById(copy.getId())
      .getAs('application/pdf');
    const pdfFile = outputFolder.createFile(pdfBlob)
      .setName(copy.getName() + '.pdf');

    // Opcjonalnie: wyślij mailem
    const email = row[headers.indexOf('Email')];
    if (email) {
      MailApp.sendEmail({
        to: email,
        subject: `Raport dla ${row[headers.indexOf('Firma')]}`,
        body: 'W załączniku przesyłam wygenerowany raport.',
        attachments: [pdfFile.getAs(MimeType.PDF)]
      });
    }

    // Usuń kopię Docs (zostaje tylko PDF)
    DriveApp.getFileById(copy.getId()).setTrashed(true);

    // Oznacz jako wygenerowany
    sheet.getRange(i + 1, headers.indexOf('Status') + 1)
         .setValue('Wygenerowano');
  }
}

Jak przygotować szablon Google Docs?

Klucz tkwi w konwencji nazewnictwa placeholderów. Używam {{NAZWA_KOLUMNY}}, gdzie nazwa kolumny to dokładnie to, co masz w nagłówku Arkusza. Dzięki temu skrypt jest uniwersalny – dodajesz nową kolumnę do Sheets, wstawiasz odpowiedni placeholder do Docs i działa bez zmiany kodu.

  • Faktura: {{Nr_faktury}}, {{Firma}}, {{Kwota_netto}}, {{Data_wystawienia}}
  • Umowa: {{Imie_Nazwisko}}, {{Stanowisko}}, {{Wynagrodzenie}}
  • Raport miesięczny: {{Okres}}, {{Przychod}}, {{Koszty}}, {{Marza}}

Automatyczny trigger – generowanie bez kliknięcia

Największa wartość skryptu pojawia się, gdy nikt nie musi go uruchamiać ręcznie. Apps Script obsługuje dwa typy triggerów przydatnych przy generowaniu PDF:

Trigger czasowy – uruchamia skrypt codziennie o określonej godzinie (np. pierwsze dni miesiąca = faktury miesięczne):

function setupMonthlyTrigger() {
  ScriptApp.newTrigger('generatePDFReports')
    .timeBased()
    .onMonthDay(1)   // 1. dzień miesiąca
    .atHour(7)       // o 07:00
    .create();
}

Trigger onFormSubmit – generuje PDF natychmiast po wypełnieniu formularza Google Forms (np. zlecenie serwisowe → PDF potwierdzenia → e-mail do klienta). Szczegółowy poradnik o formularzach Google Forms i triggerach.

Przypadki użycia według działu

Dział Typ dokumentu Trigger Oszczędność
Finanse Faktury, potwierdzenia płatności 1. dzień miesiąca ~4h/mies.
HR Umowy o pracę, aneksy Nowy wiersz w Sheets ~2h/mies.
Sprzedaż B2B Oferty, potwierdzenia zamówień onFormSubmit ~6h/mies.
Marketing Raporty miesięczne dla klientów Trigger miesięczny ~8h/mies.

Ograniczenia i limity Apps Script

Apps Script ma kilka limitów, o których warto wiedzieć przed wdrożeniem:

  • 6 minut – maksymalny czas wykonania jednego uruchomienia. Przy 500+ dokumentach trzeba zastosować batching.
  • 250 MB/dzień – limit tworzenia plików na Dysku (konto darmowe).
  • 100 maili/dzień – Gmail darmowy. Google Workspace B2B: 1 500/dzień.

Dla dużych wolumenów stosuję technikę „batch + continuation token" – skrypt przetwarza 50 plików, zapisuje stan w PropertiesService i kontynuuje przy następnym uruchomieniu triggera. Oznacza to, że 500 dokumentów zostanie wygenerowanych w 10 cyklach bez przekraczania limitu czasu.

Generowanie PDF to często tylko jeden etap w większym pipeline. W moich wdrożeniach łączę go z:

  • Automatycznym wysyłaniem przypomnień – jeśli klient nie opłacił faktury, skrypt wysyła przypomnienie z załączonym PDF po X dniach.
  • Webhokami i API – zewnętrzny system (np. CRM) triggeruje generowanie dokumentu przez HTTP request do Apps Script jako Web App.
„Generowanie faktury nie powinno wymagać ludzkiego kliknięcia. Jeśli dane są w arkuszu – PDF powinien pojawić się na Dysku sam, bez pytania."