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}}

Integracja z innymi automatyzacjami

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.
  • Automatycznym raportowaniem w Looker Studioharmonogram wysyłki raportów PDF bezpośrednio z dashboardu.
  • Webhokami i API — zewnętrzny system (np. CRM) triggeruje generowanie dokumentu przez HTTP request.
„Generowanie faktury nie powinno wymagać ludzkiego kliknięcia. Jeśli dane są w arkuszu — PDF powinien pojawić się na Dysku sam, bez pytania."

Ograniczenia i limity

Apps Script ma kilka limitów, o których warto wiedzieć:

  • 6 minut — maksymalny czas wykonania jednego uruchomienia skryptu. Przy 500+ dokumentach trzeba zastosować batching.
  • 250 MB/dzień — limit tworzenia plików na Dysku (darmowe konto).
  • 100 maili/dzień — na darmowym Gmailu. Na Google Workspace B2B jest to 1500.

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.