Коли замовлення приходять із сайту, Google Forms, Telegram і дзвінків, хаос починається не в коді. Він починається в момент, коли незрозуміло, хто взяв заявку, чи підтвердив клієнт деталі, чи оплачено замовлення і чому доставка ще не отримала товар. Тому автоматизація обробки замовлень має починатися не з "розумного ШІ", а з простого операційного ланцюга: форма або webhook створює рядок у Google Sheets, Telegram одразу показує менеджеру картку замовлення, а статуси фіксують кожен крок.

Схема автоматизації обробки замовлень: форма, webhook, Google Sheets, Telegram і статуси
Схема автоматизації обробки замовлень: форма, webhook, Google Sheets, Telegram і статуси

Це не повноцінна CRM і не заміна ERP. Для малого бізнесу часто достатньо легшого шару контролю, який не змушує команду переїжджати в нову систему. Якщо заявки вже падають у таблиці, а менеджери живуть у Telegram, краще спочатку зібрати стабільний процес навколо цих інструментів. Такий підхід добре продовжує логіку інтеграції з Telegram і Slack для клієнтської підтримки, але тут фокус не на повідомленнях, а на життєвому циклі замовлення.

Чому замовлення губляться

Зазвичай проблема виглядає як людський фактор, але майже завжди причина в процесі. Заявка прийшла в одну вкладку, менеджер відповів у месенджері, оплату перевірили в іншому кабінеті, а доставку попросили "передати потім". Поки замовлень десять на тиждень, це ще тримається на пам'яті. Коли їх стає більше, пам'ять перетворюється на слабке місце.

Типові симптоми:

  • у таблиці є заявка, але немає відповідального;
  • менеджер не бачить, чи замовлення вже підтверджене;
  • клієнт повторно питає те, що вже було погоджено;
  • доставка отримує неповні дані;
  • власник бачить продажі постфактум, а не поточну чергу;
  • скасовані замовлення не мають причини, тому помилки повторюються.

Автоматизація замовлень має прибрати не людей із процесу, а сліпі місця. Кожен рядок повинен відповідати на три питання: що це за замовлення, у якому воно статусі і хто за нього відповідає.

Мінімальна статусна модель

Без статусів Google Sheets швидко стає звалищем рядків. Статусна модель робить таблицю робочим інтерфейсом, а не архівом заявок.

Статусна модель обробки замовлення: new, confirmed, paid, shipped, done, failed
Статусна модель обробки замовлення: new, confirmed, paid, shipped, done, failed

Для першої версії достатньо шести статусів:

СтатусЩо означаєХто змінює
newзамовлення щойно створенесистема
confirmedменеджер підтвердив деталі з клієнтомменеджер
paidоплата отримана або підтвердженаменеджер/оператор
shippedзамовлення передане в доставкулогістика
doneзамовлення завершенеменеджер
failedскасування, дубль або помилкаменеджер

Ця модель навмисно проста. Не треба одразу додавати 18 статусів, якщо команда не буде ними користуватися. Краще шість зрозумілих станів, які реально оновлюються щодня, ніж красива схема, де половина рядків зависає в невідомому стані.

Як форма перетворюється на рядок у Sheets

Перший технічний крок - зробити так, щоб кожна заявка автоматично отримувала order_id і потрапляла в таблицю. Джерелом може бути форма сайту, Google Forms, Telegram-бот або будь-який webhook. Важливо, щоб у таблицю записувався не просто набір полів, а контрольований об'єкт.

Пайплайн замовлення: клієнтська форма, webhook endpoint, Google Sheets і Telegram-картка
Пайплайн замовлення: клієнтська форма, webhook endpoint, Google Sheets і Telegram-картка

Мінімальна структура таблиці:

ПолеНавіщо потрібно
order_idстабільний ідентифікатор замовлення
created_atколи заявка потрапила в систему
client_nameім'я клієнта
phoneосновний контакт
productщо замовили
amountсума або очікувана сума
sourceсайт, форма, Telegram, реклама
statusпоточний етап
managerхто взяв у роботу
last_updateколи статус змінювався востаннє
commentкоротка операційна нотатка

Apps Script endpoint може виглядати так:

function doPost(e) {
  const payload = JSON.parse(e.postData.contents || "{}");
  const order = normalizeOrder(payload);

  appendOrderToSheet(order);
  sendTelegramOrderCard(order);

  return ContentService
    .createTextOutput(JSON.stringify({ ok: true, order_id: order.order_id }))
    .setMimeType(ContentService.MimeType.JSON);
}

function normalizeOrder(input) {
  return {
    order_id: generateOrderId(),
    created_at: new Date().toISOString(),
    client_name: String(input.client_name || "").trim(),
    phone: String(input.phone || "").trim(),
    product: String(input.product || "").trim(),
    amount: Number(input.amount || 0),
    source: String(input.source || "site"),
    status: "new",
    manager: "",
    last_update: new Date().toISOString(),
    comment: ""
  };
}

У першій версії не треба ускладнювати. Головне - щоб будь-яке замовлення створювалося однаково, з однаковими полями й однаковим стартовим статусом.

Генерація order_id без дублювання

order_id не повинен бути просто номером рядка. Рядки можуть сортуватися, видалятися, переноситися, а ідентифікатор має залишатися стабільним. Для малого процесу достатньо комбінації дати й короткого випадкового хвоста.

function generateOrderId() {
  const date = Utilities.formatDate(new Date(), "Europe/Kyiv", "yyyyMMdd");
  const suffix = Math.random().toString(36).slice(2, 7).toUpperCase();
  return `ORD-${date}-${suffix}`;
}

Для більших обсягів краще перевіряти унікальність перед записом або тримати окремий лічильник у PropertiesService. Але навіть такий формат уже кращий за "замовлення з рядка 42", бо ним можна посилатися в Telegram, коментарях і доставці.

Запис замовлення в Google Sheets

Коли об'єкт нормалізований, його можна записувати в таблицю.

function appendOrderToSheet(order) {
  const sheet = SpreadsheetApp.getActive().getSheetByName("Orders");

  sheet.appendRow([
    order.order_id,
    order.created_at,
    order.client_name,
    order.phone,
    order.product,
    order.amount,
    order.source,
    order.status,
    order.manager,
    order.last_update,
    order.comment
  ]);
}

Цей код не робить нічого "магічного", і це добре. На старті важливіше мати прозорий запис, ніж складну архітектуру. Якщо процес виросте, той самий webhook можна перенести в Node.js мікросервіс, як у підході з мікросервісами для Google Workspace.

Telegram як робочий інтерфейс менеджера

Менеджер не має кожні п'ять хвилин відкривати таблицю, щоб помітити нове замовлення. Таблиця - це база й контроль, а Telegram - швидкий робочий сигнал.

Telegram-картка нового замовлення з order_id, товаром, сумою, клієнтом і кнопками статусів
Telegram-картка нового замовлення з order_id, товаром, сумою, клієнтом і кнопками статусів

Повідомлення має бути коротким:

function sendTelegramOrderCard(order) {
  const token = PropertiesService.getScriptProperties().getProperty("TG_TOKEN");
  const chatId = PropertiesService.getScriptProperties().getProperty("TG_CHAT_ID");

  const text = [
    `Нове замовлення: ${order.order_id}`,
    `Клієнт: ${order.client_name}`,
    `Телефон: ${order.phone}`,
    `Товар: ${order.product}`,
    `Сума: ${order.amount}`,
    `Джерело: ${order.source}`,
    `Статус: ${order.status}`
  ].join("
");

  UrlFetchApp.fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
    method: "post",
    contentType: "application/json",
    payload: JSON.stringify({
      chat_id: chatId,
      text
    })
  });
}

У наступній версії можна додати inline-кнопки: "Взяти в роботу", "Підтверджено", "Оплачено", "Скасовано". Але навіть просте повідомлення вже скорочує час першої реакції, бо менеджер бачить замовлення там, де він реально працює.

Що логувати в кожному замовленні

Найцінніша частина такої системи - не сам факт запису в таблицю, а історія змін. Якщо статус змінився з confirmed на failed, треба знати, хто це зробив і чому. Інакше через тиждень неможливо зрозуміти, де процес ламається.

Поля журналу замовлення: status, manager, last_update, comment і причина зміни
Поля журналу замовлення: status, manager, last_update, comment і причина зміни

Мінімальне правило:

  • кожна зміна статусу оновлює last_update;
  • кожне замовлення має manager;
  • для failed обов'язковий comment;
  • статус не змінюється без запису відповідального;
  • дубль не видаляється мовчки, а позначається як failed із причиною duplicate.

Оновлення статусу можна зробити окремою функцією:

function updateOrderStatus(orderId, status, manager, comment) {
  const sheet = SpreadsheetApp.getActive().getSheetByName("Orders");
  const values = sheet.getDataRange().getValues();
  const headers = values[0];

  const idCol = headers.indexOf("order_id");
  const statusCol = headers.indexOf("status");
  const managerCol = headers.indexOf("manager");
  const updatedCol = headers.indexOf("last_update");
  const commentCol = headers.indexOf("comment");

  for (let row = 1; row < values.length; row++) {
    if (values[row][idCol] !== orderId) continue;

    sheet.getRange(row + 1, statusCol + 1).setValue(status);
    sheet.getRange(row + 1, managerCol + 1).setValue(manager);
    sheet.getRange(row + 1, updatedCol + 1).setValue(new Date().toISOString());
    sheet.getRange(row + 1, commentCol + 1).setValue(comment || "");
    return true;
  }

  throw new Error(`Order not found: ${orderId}`);
}

Ця функція здається дрібницею, але саме вона прибирає ситуацію "хтось щось змінив, але ніхто не знає хто". Для операційного процесу це важливіше за красивий інтерфейс.

Як статуси прибрали питання "хто взяв це замовлення?"

В одному з робочих сценаріїв проблема була не в кількості замовлень, а в тому, що вони зависали між менеджером і доставкою. Менеджер бачив заявку, міг написати клієнту, але не завжди фіксував, що саме зробив. Доставка іноді отримувала неповні дані, а власник бачив проблему тільки тоді, коли клієнт уже повторно питав про статус.

Ми не починали з CRM. Спочатку додали три речі: manager, status і last_update. Нові заявки автоматично приходили в Telegram, менеджер після першого контакту ставив confirmed, після оплати - paid, а перед передачею в доставку - shipped.

Результат був простий і вимірюваний: стало менше ручних уточнень у чаті, перша реакція на нову заявку стала швидшою, а проблемні замовлення почали фільтруватися за статусом new або старим last_update. Тобто команда перестала питати "хто взяв це замовлення?" і почала дивитися в один зрозумілий рядок.

Типові помилки в автоматизації замовлень

Є кілька речей, які краще закласти одразу:

  1. Дублікати order_id. Якщо ідентифікатор не унікальний, Telegram, таблиця і менеджер починають говорити про різні замовлення під одним номером.
  2. Немає last_update. Статус без часу оновлення не показує, чи замовлення живе, чи зависло.
  3. Статус змінюється без відповідального. Потім неможливо зрозуміти, хто підтвердив оплату або скасував заявку.
  4. Коментар необов'язковий для скасування. failed без причини не дає матеріалу для покращення процесу.
  5. Telegram замінює таблицю. Повідомлення зручне для реакції, але джерелом правди має залишатися таблиця або база.
  6. Занадто складна статусна модель. Якщо менеджер не розуміє різницю між статусами, він перестане їх оновлювати.

Що зробити першим

Починати варто не з великої інтеграції, а з короткого аудиту:

  1. Випишіть усі джерела замовлень: сайт, форма, Telegram, дзвінки, маркетплейси.
  2. Створіть одну таблицю Orders з мінімальними полями.
  3. Визначте шість статусів і правила переходу між ними.
  4. Підключіть webhook для одного джерела, а не для всіх одразу.
  5. Надішліть нове замовлення в Telegram менеджеру.
  6. Через тиждень подивіться, які статуси зависають і чому.

Автоматизація обробки замовлень працює тоді, коли вона зрозуміла менеджеру. Не треба будувати складну CRM, якщо бізнесу зараз потрібен контроль над чергою, відповідальними й статусами. Проста таблиця, стабільний orderid, Telegram-сигнал і чесний lastupdate часто дають більше користі, ніж дорогий інструмент, який команда заповнює тільки перші три дні.