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:
- Szablon — Google Docs z placeholderami (np.
{{NAZWA_FIRMY}},{{KWOTA}},{{DATA}}). - Dane — wiersz w Google Sheets z konkretnymi wartościami dla każdego klienta/raportu.
- 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 Studio — harmonogram 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.