Автоматизація комерційних пропозицій: як зібрати Google Docs, PDF і Gmail в один процес
У комерційній пропозиції більша частина роботи повторюється: підставити компанію, контакт, послуги, ціну, строк дії та менеджера. Тому автоматизація комерційних пропозицій починається не з ШІ, а з контрольованого шаблону й чітких статусів.

Процес можна зібрати на Google Sheets, Docs, Drive та Gmail. Менеджер готує дані, Apps Script створює копію документа, PDF і чернетку листа. Відправлення дозволяється після погодження. Це продовжує CRM автоматизацію з чистими лідами: спочатку впорядковуємо контакт, потім створюємо документ.
Чому менеджери витрачають час на КП
Проблема з'являється, коли кожен менеджер зберігає власний шаблон і копіює попередню пропозицію. У новому PDF може залишитися чуже ім'я, стара ціна або строк дії.
Типові симптоми:
- файли називаються
КПfinal,КПnewіКПfinal2; - невідомо, яка версія була відправлена клієнту;
- ціна в документі відрізняється від погодженої в таблиці;
- лист відправили, але поле
sent_atніде не зафіксували;
Ціну, юридичні умови й склад послуг підтверджує людина. Скрипт лише переносить затверджені поля.
Які дані потрібні для генерації
Для першої версії достатньо одного аркуша Proposals:
| Поле | Призначення |
|---|---|
proposal_id | стабільний номер пропозиції |
client_name | ім'я контактної особи |
company | назва компанії |
email | адреса одержувача |
services | погоджений перелік робіт |
price | затверджена сума |
currency | валюта |
valid_until | строк дії пропозиції |
manager | відповідальний |
status | поточний стан |
document_url | посилання на Google Docs |
pdf_url | посилання на збережений PDF |
sent_at | дата й час відправлення |
proposal_id не варто прив'язувати до номера рядка: таблицю можуть сортувати. Підійде значення PROP-20260607-A4F2. Дані з AI-помічника менеджера перед дзвінком можна використати для КП, але модель не повинна вигадувати ціну.
Шаблон Google Docs із плейсхолдерами

У шаблоні зручно використовувати маркери:
Компанія: {{COMPANY}}
Контакт: {{CLIENT_NAME}}
Послуги: {{SERVICES}}
Вартість: {{PRICE}} {{CURRENCY}}
Пропозиція дійсна до: {{VALID_UNTIL}}
Менеджер: {{MANAGER}}Apps Script може створити копію шаблону через Drive, а потім відкрити її через DocumentApp. Офіційний Document service підтримує відкриття й редагування Google Docs, а replaceText() працює з регулярними виразами.
function createProposalFromTemplate(data) {
const templateId = getSetting("PROPOSAL_TEMPLATE_ID");
const folderId = getSetting("PROPOSALS_FOLDER_ID");
const folder = DriveApp.getFolderById(folderId);
const name = `${data.proposal_id} - ${data.company}`;
const copy = DriveApp.getFileById(templateId).makeCopy(name, folder);
const doc = DocumentApp.openById(copy.getId());
replaceProposalPlaceholders(doc, data);
doc.saveAndClose();
return {
fileId: copy.getId(),
documentUrl: copy.getUrl()
};
}Кожна генерація створює окремий файл і не перезаписує шаблон.
function replaceProposalPlaceholders(doc, data) {
const body = doc.getBody();
const values = {
COMPANY: data.company,
CLIENT_NAME: data.client_name,
SERVICES: data.services,
PRICE: formatMoney(data.price),
CURRENCY: data.currency,
VALID_UNTIL: data.valid_until,
MANAGER: data.manager
};
Object.entries(values).forEach(([key, value]) => {
body.replaceText(`\\{\\{${key}\\}\\}`, String(value || ""));
});
}Порожній email або нульова ціна мають переводити рядок у error.
Як створити PDF і підготувати лист
Google Docs можна отримати як PDF через офіційний Drive service. Для контрольованого процесу спочатку краще створювати чернетку.
function exportProposalPdf(fileId, proposalId) {
const pdfFolder = DriveApp.getFolderById(
getSetting("PROPOSALS_PDF_FOLDER_ID")
);
const blob = DriveApp
.getFileById(fileId)
.getAs(MimeType.PDF)
.setName(`${proposalId}.pdf`);
const pdfFile = pdfFolder.createFile(blob);
return {
blob,
pdfUrl: pdfFile.getUrl()
};
}Менеджер має бачити одержувача, тему й вкладення до відправки. Чернетки та вкладення описані в офіційному Gmail service.
function createProposalDraft(data, pdfBlob) {
const subject = `Комерційна пропозиція ${data.proposal_id}`;
const body = [
`Добрий день, ${data.client_name}!`,
"",
"Надсилаю погоджену комерційну пропозицію у вкладенні.",
`Вона дійсна до ${data.valid_until}.`,
"",
`З повагою, ${data.manager}`
].join("
");
return GmailApp.createDraft(data.email, subject, body, {
attachments: [pdfBlob]
});
}Функція відправлення має повторно прочитати рядок і перевірити status === "approved". Як у системі обробки замовлень зі статусами, дія виконується лише з дозволеного стану.

function sendApprovedProposal(proposalId) {
const data = getProposalById(proposalId);
if (!data || data.status !== "approved") {
throw new Error("Proposal must be approved before sending");
}
const draft = GmailApp.getDraft(data.draft_id);
draft.send();
updateProposalFields(proposalId, {
status: "sent",
sent_at: new Date().toISOString()
});
}Статуси та версії пропозиції

Мінімальна статусна модель:
| Статус | Що відбувається |
|---|---|
draft | менеджер заповнює дані |
ready | усі обов'язкові поля пройшли перевірку |
approved | відповідальний підтвердив ціну й умови |
sent | лист відправлено, sent_at заповнено |
expired | строк дії завершився |
error | документ або лист не вдалося підготувати |
Таблиця зберігає URL документа, PDF і час зміни статусу. Після правок створіть PROP-20260607-A4F2-v2, поверніть статус у ready і погодьте повторно.
Шаблон, PDF і таблицю з комерційними умовами не слід відкривати як Anyone with the link. Для інтеграцій також корисна архітектура Apps Script webhook-сервера.
Як шаблон прибрав помилки у версіях комерційної пропозиції

У робочому сценарії я почав не з генерації тексту, а з реєстру пропозицій. До цього менеджер копіював попередній Google Docs, змінював видимі поля й експортував PDF. Найнеприємніша помилка була не технічною: у документі могла залишитися стара умова, яку не помітили перед відправленням.
Я виніс ключові значення в окремі колонки, додав proposalid, status, documenturl, pdfurl і sentat. Скрипт перестав редагувати старий файл та почав створювати нову копію шаблону для кожної версії. Перед відправленням залишив ручний approval.
Результат перевіряється фактами: для кожного PDF видно джерельний рядок, актуальну версію, відповідального й дату відправлення. Якщо клієнт просить змінити склад робіт, команда створює v2, а не намагається згадати, який із файлів із назвою final був останнім.
Практичний підсумок
Автоматизація комерційних пропозицій працює, коли дані структуровані, шаблон незмінний, а генерація відокремлена від погодження й відправлення. Google Sheets зберігає стан, Google Docs формує документ, Drive тримає версії та PDF, Gmail готує чернетку.
Почніть з одного шаблону й шести статусів. Не передавайте ШІ право вигадувати ціни або юридичні умови. Нехай скрипт прибирає копіювання, а людина зберігає контроль над комерційним рішенням.
Останні статті

Google Apps Script security: токени, права доступу і безпечні webhook-автоматизації
Google Apps Script security часто згадують тільки після того, як автоматизація вже працює. Таблиця приймає заявки, Web App отримує webhook-и, Telegram-бот відправляє пов…

OpenAI API cost control: як рахувати токени, ставити ліміти і не отримати несподіваний рахунок
OpenAI API cost control - це не страх перед LLM, а нормальна фінансова гігієна автоматизації. Якщо модель допомагає обробляти заявки, писати summary, класифікувати зверн…

Надійність автоматизації бізнес-процесів: черги, повтори і idempotency без великої інфраструктури
Надійність автоматизації бізнес-процесів починається не з Kubernetes, RabbitMQ або складної cloud-архітектури. У малому бізнесі вона часто починається з простішого питан…

RAG для бізнесу: як зробити внутрішній чат-бот по регламентах, FAQ і Google Docs
RAG для бізнесу потрібен не для того, щоб зробити ще одного "розумного чат-бота". Його нормальна задача простіша: дати співробітнику відповідь на основі внутрі…

CRM автоматизація: як прибирати дублікати лідів і ставити пріоритет менеджеру
CRM автоматизація часто починається не з купівлі великої CRM, а з менш романтичної задачі: прибрати дублікати лідів і зрозуміти, які заявки справді потребують швидкої ре…

AI помічник для продажів: summary клієнта перед дзвінком
Менеджер рідко провалює перший дзвінок через те, що не вміє говорити з клієнтом. Частіше проблема простіша: перед очима є тільки ім'я, телефон і короткий коментар із…