gdamian.pl
← Wszystkie wpisy
11 min

Automatyzacja ofertowania: wygeneruj ofertę PDF z CRM w 6 krokach (n8n) 

Damian GębalaAutor

Automatyzacja ofertowania w n8n to szereg węzłów (kroków), w którym zmiana statusu w CRM uruchamia przepływ: pobranie danych klienta, złożenie treści oferty, wygenerowanie pliku, wysyłka mailem i zapis kopii. Oferta PDF wychodzi sama, bez otwierania Worda. Poniżej rozbijam ten przepływ na sześć kroków, z nazwami węzłów i konkretnymi ustawieniami, oraz pokazuję miejsce, w którym dokumentacja n8n nie zawiera operacji generującej PDF.

Co tak naprawdę automatyzuje ten przepływ

Nie sprzedaż. Tu nie ma nic, co dzwoni do klienta czy kwalifikuje leady. Ten przepływ przenosi dokument: bierze fakty z CRM, składa z nich ofertę, wysyła i odkłada. Dopiero to jest automatyzacja, którą da się zmierzyć godzinami.

Różnica widać na liczniku wykonań. n8n rozlicza cały przebieg workflow jako jedno wykonanie, niezależnie od liczby węzłów: „An execution is a single run of your entire workflow. It doesn’t matter how many steps are in the workflow” - tyle stoi w cenniku. Sześć węzłów to jedno wykonanie, nie sześć.

Zakład, na którym opiera się cały tutorial: oferta jest zawsze ta sama w strukturze, a różni się nazwiskiem, numerem, datą i pozycjami. Jeśli za każdym razem ktoś układa ją od nowa, ten przepływ właśnie zastępuje powtarzalną robotę. Ofertowanie zwykle wchodzi na listę procesów do automatyzacji w pierwszej kolejności, ale nie zawsze jest najlepszym startem. Jeśli n8n jest dla Ciebie nowe, zacznij od pierwszej automatyzacji w n8n krok po kroku.

Krok 1: Webhook albo harmonogram jako wejście

Przepływ zaczyna się od wyzwalacza. W n8n węzeł Webhook daje dwa adresy: testowy i produkcyjny, a produkcyjny rejestruje się dopiero po publikacji workflow. W praktyce wygląda to tak: budujesz na adresie testowym, sprawdzasz na dziesięciu prawdziwych zdarzeniach, a na koniec przełączasz wyzwalacz i publikujesz.

Webhook przyjmuje do 16 MB ładunku. Limit jest w dokumentacji podany wprost: „The webhook maximum payload size is 16MB”. Przy samodzielnej instalacji zmienisz go zmienną N8N_PAYLOAD_SIZE_MAX, ale przy ofercie z kilkunastoma pozycjami nie zbliżysz się do tej granicy.

Dwie opcje bezpieczeństwa warto włączyć od razu. Lista dozwolonych adresów IP odcina dostęp spoza siebie błędem 403. Warunek „Only Run If” to wyrażenie, które odpala przepływ tylko dla właściwych zdarzeń, np. gdy w ładunku jest identyfikator leada. Bez niego każde przypadkowe wywołanie uruchomi ofertowanie dla byle jakich danych.

Alternatywą jest Schedule Trigger, czyli harmonogram w formacie cron. Cron ma sześć pól, szósta gwiazda to sekundy, więc wyrażenie 0 6 * * * uruchamia przepływ codziennie o 6:00. Dwie rzeczy, o których łatwo zapomnieć: strefa czasowa na własnej instalacji domyślnie to America/New_York, a w chmurze n8n wykrywa strefę właściciela, a w razie niepowodzenia wraca do GMT. Druga: przy harmonogramie workflow trzeba zapisać i opublikować, inaczej nie ruszy.

Krok 2: Pobranie danych z CRM przez HTTP Request

Węzeł HTTP Request pozwala odpytać dowolną aplikację z API REST. Do CRM masz dwie drogi. Pierwsza to natywny węzeł aplikacji: na liście w dokumentacji są między innymi HubSpot, Salesforce, Pipedrive, Zoho CRM, Agile CRM, Freshservice i Freshworks CRM. Druga to HTTP Request z ręcznie zbudowanym zapytaniem, gdy Twojego CRM nie ma na liście albo gdy potrzebujesz konkretnego endpointu. Ten sam mechanizm, co przy łączeniu sklepu z księgowością, opisałem szerzej przy integracji sklepu, CRM i księgowości.

Kredencje obsługujesz w zakładce Authentication. Dokumentacja zaleca opcję Predefined Credential Type, gdy tylko jest dostępna, a obok niej stoi zestaw Generic credentials dla systemów bez natywnej integracji: Basic auth, Header auth, OAuth2 API, Query auth i inne. Wskazówka przy własnym CRM: w HTTP Request możesz wkleić komendę curl, a n8n zbuduje z niej zapytanie. Wada tej drogi: importowane wartości wczytują się jako tekst, więc liczby i daty trzeba ręcznie poprawić na właściwy typ.

Przy pobieraniu większej listy kluczowe są dwie opcje. Batching dzieli zapytania na pakiety - ustawiasz liczbę pozycji na paczkę i odstęp między nimi w milisekundach, a interwał zero oznacza brak odstępu. Pagination obsługuje trzy tryby: wyłączony, aktualizacja parametru w każdym żądaniu oraz tryb, w którym odpowiedź zawiera adres następnej strony. Do wskazywania licznika i adresu służą zmienne $pageCount, $request i $response, a $response daje dostęp do body, nagłówków i kodu odpowiedzi.

Drobiazgi, które oszczędzają godzinę debugowania: opcja Timeout w milisekundach, „Never Error”, która zamienia wyjątek na zwykłą odpowiedź, oraz Response Format do wyboru (Autodetect, File, JSON, Text). Dla załącznika z CRM ustawiasz File - w odpowiedzi nie ma wtedy tekstu, tylko dane binarne.

Krok 3: Złożenie treści oferty w Edit Fields i Code

Tutaj składasz treść. Węzeł Edit Fields (Set) ma dwa tryby: Manual Mapping to przeciąganie pól z danych wejściowych, JSON Output to ręcznie pisany JSON z wyrażeniami w stylu „{{ $json.id }}”. Do ofert używasz zwykle JSON Output, bo nazwy pól w ofercie (numer, pozycje, suma) rzadko pokrywają się z nazwami pól w CRM. Przydatna opcja Support Dot Notation: kropka oznacza zagnieżdżenie, więc „items.0.name” sięga w głąb listy pozycji.

Gdy w treści jest warunek, na przykład rabat progowy albo inna cena dla kontrahenta, dokładasz węzeł Code. Ma dwa tryby działania: Run Once for All Items, czyli raz dla całej paczki, oraz Run Once for Each Item, czyli osobno dla każdej pozycji. Ograniczenie Code node jest ważne przy ofertowaniu: węzeł nie ma dostępu do systemu plików ani do żadnych żądań HTTP. Jeśli potrzebujesz danych z bazy albo z sieci, musisz je pobrać w poprzednim węźle, a tutaj operujesz już tylko na tym, co jest w $json.

Drugie ograniczenie dotyczy bibliotek. W chmurze w Code node działają wyłącznie wbudowany moduł crypto i pakiet moment; własne pakiety npm importujesz dopiero przy własnej instalacji. Python jest dostępny od wersji 1.111.0 i stabilny w n8n 2, ale w chmurze nie pozwala dociągać żadnych bibliotek.

Krok 4: Plik do wysłania - i pułapka z PDF

Tu dochodzimy do miejsca, o którym większość materiałów o generowaniu PDF-ów milczy. Węzeł Convert to File zamienia dane wejściowe na plik binarny, a lista jego operacji to: Convert to CSV, HTML, ICS, JSON, ODS, RTF, Text File, XLS, XLSX oraz Move Base64 String to File. Operacji „Convert to PDF” na tej liście nie ma. PDF-ów ten węzeł nie tworzy. Węzeł Extract From File potrafi PDF tylko odczytać - w drugą stronę nie.

Są dwa sposoby, żeby oferta i tak wyszła jako PDF. Pierwszy: HTML z poprzedniego kroku wysyłasz przez HTTP Request do usługi, która renderuje dokument na PDF, i dostajesz z powrotem plik. Wtedy robisz Convert to File z operacją Move Base64 String to File, podajesz nazwę pola z ciągiem base64 i ustawiasz MIME Type. Druga droga to węzeł spoza rdzenia n8n, instalowany jako pakiet społecznościowy - dokumentacja go nie opisuje, więc przetestuj go na własnym szablonie, zanim wpuścisz na produkcję.

W obu przypadkach wynik jest taki sam: w propcji binary pojawia się plik. Dane plikowe w n8n to obiekt z polem data, które z definicji jest ciągiem base64, a opcjonalnie dokłada mimeType, fileExtension i fileName. Przy własnej instalacji sposób przechowywania ustawiasz zmienną N8N_DEFAULT_BINARY_DATA_MODE - tryby default, filesystem, database, s3 i azure. Domyślny trzyma dane binarne w pamięci.

Krok 5: Wysyłka oferty mailem

Wysyłka to węzeł Send Email działający przez serwer SMTP. Ma dwie operacje: Send, czyli wyślij i zakończ, oraz Send and Wait for Response, która czeka na odpowiedź człowieka - przydaje się, gdy handlowiec zatwierdza ofertę przed wysyłką. W formacie maila wybierasz Text, HTML albo oba.

Załącznik podłączasz opcją Attachments, w której podajesz nazwę pola binarnego. Wiele plików wpisujesz po przecinku, w jednym polu. Jeśli plik jeszcze nie jest w przepływie, dokumentacja podaje wprost, skąd go wziąć: z węzła Read/Write Files from Disk albo z HTTP Request.

Jedno ograniczenie daje się we znaki: węzeł Send Email (SMTP) nie pozwala ustawiać nagłówków In-Reply-To i References, czyli tych, które spinają wątek mailowy. Przy pojedynczej ofercie nie masz problemu. Przy follow-upie w tym samym wątku musisz sięgnąć po węzeł Gmaila albo własne rozwiązanie.

Krok 6: Zapis oferty i obsługa błędów

Kopia oferty powinna zostać tam, gdzie zespół jej szuka. W n8n są węzły Google Drive oraz poświadczenia S3, więc zapis do własnego magazynu plików jest możliwy. Zaznaczę uczciwie granicę: dokumentacja węzła Google Drive i strony S3 nie była w zestawie, na którym opierałem ten opis, więc nie podaję nazw parametrów - to sprawdź w swojej wersji dokumentacji, bo pola zmieniają się między wersjami. Przy raportach idzie to tą samą drogą, tyle że zamiast wysyłki do klienta liczy się załącznik dla zespołu, o czym pisałem przy automatyzacji powtarzalnych raportów.

Błędy obsługujesz osobnym węzłem Error Trigger albo regułą Error workflows; zmienna N8N_ERROR_TRIGGER_TYPE domyślnie wskazuje węzeł n8n-nodes-base.errorTrigger. Przy ofercie najczęstszy problem to nie wykonanie, tylko pusta oferta: potrzebujesz gałęzi „nie ma pozycji”, bo i tak musisz to ogarnąć ręcznie.

Jedno uspokojenie przed rozmową z klientem: przekroczenie limitu wykonań nie wyłącza przepływów. W cenniku stoi wprost, że przy przekroczeniu puli workflow działają dalej bez przerwania, a nadgodziny są fakturowane. Zmieni się tylko ilość przechowywanej historii, nie dostępność.

Ile to kosztuje: chmura, własny serwer, liczba wykonań

Ceny n8n Cloud podaję w euro, tak jak są na stronie cennika, z rocznym zobowiązaniem. Starter kosztuje 20 € miesięcznie przy płatności rocznej i daje 2,5 tys. wykonań miesięcznie oraz 5 wykonań współbieżnych. Pro to 50 € miesięcznie, 10 tys. wykonań i 20 wykonań współbieżnych. Business to 667 € miesięcznie przy 40 tys. wykonań, dostępny wyłącznie przy własnej instalacji. Rabat za płatność roczną to 17%. Przeliczone na rok: 240 €, 600 € i 8004 €.

Inne miejsce podaje dla tych samych planów inne liczby, więc nie mieszaj ich. Tutorial na Hostingerze pisze o 20 i 50 dolarach miesięcznie, czyli waluta i okres rozliczenia są inne niż w cenniku n8n.

Przed płatnością jest próbny okres: 1000 wykonań, 5 wykonań współbieżnych i 180-sekundowy limit czasu jednego wykonania, bez karty płatniczej. Limit warto zapamiętać - generowanie dużej oferty z kilkuset pozycjami wraz z renderowaniem PDF potrafi do niego podejść, a wtedy przepływ przerwie się w połowie.

Własna instalacja kosztuje zero licencji: bez klucza n8n działa jako darmowa wersja Community. Płaci się za serwer. Przykładowa kwota z artykułu Hostingera to 8,99 USD miesięcznie za najmniejszy plan KVM 2, podana bez VAT - to koszt hostingu, nie licencji. n8n działa na porcie 5678, a jednolinijkowa instalacja wygląda tak: curl -fsSL https://get.n8n.io | sh, z zastrzeżeniem, że wymaga Dockera na Linuksie albo macOS.

Jeszcze jedna liczba, bo przy ofertowaniu pada pytanie o skalę: n8n deklaruje, że obsługuje do 220 wykonań na sekundę na pojedynczej instancji. To maksimum dla testu, nie przepustowość Twojego CRM. Liczba integracji różni się zależnie od strony: strona funkcji mówi o ponad 500, opis projektu na GitHubie o ponad 1500, a sekcja „About” w tym samym repozytorium wciąż o ponad 400.

Co się psuje przy większym ruchu

Przy kilku ofertach dziennie nie musisz o tym myśleć. Przy kilkuset zaczyna mieć znaczenie tryb kolejki, bo wiele węzłów przetwarza jednocześnie kilka przepływów. Konkretna pułapka: n8n nie obsługuje trybu kolejki, gdy dane binarne trzymane są w systemie plików. Jeśli twoje oferty mają być plikami, potrzebujesz zewnętrznego magazynu, czyli S3. Zanim jednak kupisz własny serwer, przeczytaj, dlaczego polskie firmy automatyzują właśnie w n8n - to odpowiada na pytanie, co zyskujesz, przenosząc wszystko na własną instalację.

Limity są policzone i opisane. Odpowiedź w trybie kolejki nie przekracza 64 MiB (zmienna N8N_WEBHOOK_RESPONSE_RELAY_SIZE_MAX, domyślnie 64), a w Redis trzeba zarezerwować około 1,5 raza tyle pamięci na każdą odpowiedź w locie. Worker domyślnie ciągnie 10 zadań naraz, a dokumentacja zaleca współbieżność 5 lub więcej. Plik binarny w bazie mieści się do 1 GB, co steruje zmienna N8N_BINARY_DATA_DATABASE_MAX_FILE_SIZE.

Dwie rzeczy psują środowisko produkcyjne najczęściej. Klucz szyfrowania instancji głównej musi być wspólny dla wszystkich workerów i procesorów webhooków, bo inaczej nie odczytają danych zaszyfrowanych przez main. I drugie: tryb kolejki na SQLite nie jest zalecany, a rozproszony system na SQLite w ogóle nie jest wspierany. Do kolejki idzie PostgreSQL.

Zanim zaczniesz: czy to w ogóle się opłaca

Ten przepływ ma sens, gdy ofertę składa człowiek robiący to kilka razy w tygodniu, a treść jest stała. Nie ma go, gdy każda oferta powstaje z rozmowy - wtedy automatyzujesz pustkę i dostajesz kolejny element, który coś psuje.

Kolejność, która działa: najpierw jeden proces, jedna osoba odpowiedzialna, jeden mierzalny wynik w godzinach. Jak to policzyć przed wydaniem złotówki, opisałem w tekście o rachunku zwrotu z automatyzacji. Przy oferowaniu liczy się jedna liczba: ile godzin dziennie znika na składanie i wysyłanie ofert.

Robisz coś podobnego u siebie?Napisz do mnie

Masz proces, który zjada tydzień pracy? Odzyskajmy ten tydzień.

Napisz do mnie