ОБЛІК ЛІДІВ І ПРОДАЖІВ У GOOGLE SHEETS
Демонстраційний проєкт для портфоліо Viktoriia Boiko

ДАНІ
60 синтетичних запитів. Усі ID, суми, дати й ролі створені для демонстрації.
Персональних даних, реальних клієнтів і підключення до CRM немає.
Валюта одна: гривня. Один рядок — один лід.

ЩО ПРАЦЮЄ У ТАБЛИЦІ
«Огляд»: продажі, вартість відкритих запитів, частка виграних серед усіх
валідних лідів, розподіли за статусом, каналом і відповідальним.
«Ліди»: поля для введення A:J, формули K:M, 500 місць для записів.
«Довідники»: п’ять статусів, чотири канали та три умовні ролі менеджерів.

Контакт прострочений, якщо лід відкритий, рядок валідний, а дата наступного
контакту раніше дати звіту в «Огляд»!I3. Контакт на дату звіту ще не прострочений.
Дата звіту встановлена на 12.10.2026 і змінюється вручну.

Частка виграних = виграні / всі валідні ліди. Це не win rate серед закритих.
Продажі = сума лише валідних лідів зі статусом «Виграно». Це сума виграних
угод у моделі, а не підтверджені банківські надходження чи бухгалтерський дохід.
Потенціал відкритих запитів не є прогнозом продажів.
Некоректні рядки видно в колонці L і лічильнику на огляді; вони не входять у KPI.

РУЧНЕ ВВЕДЕННЯ
1. Зробіть власну копію публічної таблиці: Файл → Створити копію.
2. На аркуші «Ліди» додайте рядок у A:J до рядка 506 включно.
3. Вкажіть унікальний ID на кшталт L-0061, дату створення, канал,
   відповідального, статус, суму та час оновлення.
4. Для Новий / У роботі / Пропозиція вкажіть наступний контакт, а дату
   закриття залиште порожньою. Для Виграно / Програно — навпаки.
5. Не змінюйте формули K:M. Фільтруйте і сортуйте всю таблицю, а не одну колонку.
6. Після встановлення скрипту ручна правка A:J автоматично оновлює H.
   Без скрипту вкажіть час оновлення вручну. Часовий пояс таблиці: UTC.
   Скрипт після імпорту та ручних правок відновлює формат дат ДД.ММ.РРРР,
   а для часу оновлення — ДД.ММ.РРРР ГГ:ХХ.
   У нативній таблиці колонки B, G, H, J мають тип «Не визначено»
   (COLUMN_TYPE_UNSPECIFIED) і звичайний числовий формат дати/часу.
   Не задавайте їм фіксований тип колонки таблиці DATE або DATE_TIME:
   він блокує setNumberFormat. Якщо тип змінено, помилка форматування може
   виникнути вже після запису даних. Перевірте результат, перш ніж повторювати імпорт.

CSV ТА ПОВТОРНИЙ ІМПОРТ
Code.gs працює лише з поточною таблицею. Не звертається до Drive чи мережі.
Меню Lead Desk → Імпортувати CSV приймає вставлений текст із заголовком:
lead_id,created_at,channel,owner,status,amount_uah,closed_at,updated_at,note,next_contact_at

Спочатку «Перевірити» показує кількість нових, оновлених та незмінених записів.
«Застосувати» повторно перевіряє актуальний стан таблиці під document lock.
Одна помилка скасовує весь пакет до запису; причини містять номери рядків.
Успішна операція оновлює A:J одним setValues. Сторонні зміни користувачів під
час операції не блокуються document lock: на час імпорту не редагуйте таблицю.

Правила:
- ID стабільний, формат L-0001. Новий ID додається, наявний — оновлюється.
- Створення не змінюється для наявного ID.
- Оновлення з іншими значеннями має бути новішим за поточний updated_at.
- Повторення ідентичного запису нічого не змінює і не створює дубль.
- Повторений ID усередині CSV відхиляє пакет, навіть якщо рядки ідентичні.
- Порожні обов’язкові поля, невідомі категорії, некоректні дати, від’ємна
  сума, формульний текст у примітці, дубль ID у таблиці відхиляють пакет.
- amount_uah: число 0…100000000, до двох десяткових знаків, десятковий роздільник — крапка.
- Дати — YYYY-MM-DD; updated_at — UTC ISO, наприклад 2026-10-12T10:00:00.000Z.
- CSV використовує кому як роздільник і стандартне екранування лапками.
- Місткість — 500 лідів. Для розширення узгоджено збільшіть формули, таблицю
  та LEAD_CFG.capacity; поточний демопроєкт відхиляє перевищення ліміту.

ДЕМОНСТРАЦІЙНИЙ ПРОГІН
Початково: 60 лідів, 15 виграних, 15 програних, 30 відкритих.
Продажі 280000 грн; потенціал відкритих 562500 грн; 14 прострочених контактів.
demo-import.csv оновлює L-0001 до «Виграно» на 4500 грн і додає L-0061.
Після першого імпорту: 61 лід, 16 виграних, продажі 284500 грн,
потенціал 576000 грн, 13 прострочених контактів. Повторний імпорт: 0 змін.
runDemoImport() у редакторі Apps Script виконує той самий приклад.
Не запускайте його у власній робочій таблиці з реальними записами L-0001/L-0061.

ВСТАНОВЛЕННЯ CODE.GS У ВЛАСНІЙ КОПІЇ
1. Розширення → Apps Script. Вставте Code.gs замість початкового коду.
2. Збережіть. Поверніться до таблиці й оновіть сторінку: з’явиться Lead Desk.
3. При першому запуску підтвердьте доступ до поточної таблиці.
4. Меню «Перевірити структуру» перевіряє наявність 500 рядків формул.
У коді є @OnlyCurrentDoc. Власник копії сам дозволяє виконання у своїй таблиці.
Google описує копіювання bound scripts разом із таблицею тут:
https://developers.google.com/apps-script/guides/bound

ФАЙЛИ
Code.gs — код для прив’язаної таблиці.
leads-seed.csv — початкові демонстраційні записи.
demo-import.csv — відтворюваний приклад оновлення й додавання.
tests.mjs — локальні тести чистої логіки, запуск: node tests.mjs (Node.js 20+).
summary.json — перевірені метрики, діапазони, вимоги до нативної таблиці.
validation.json — результати локальних перевірок.
native-verification.json — окремий запис перевірки у Google Sheets.

НАТИВНА ПЕРЕВІРКА
Code.gs встановлено як прив’язаний скрипт у демонстраційну Google-таблицю.
Два послідовні запуски runDemoImport() у Google підтвердили додавання,
оновлення й ідемпотентність: 61 лід, 16 виграних, 284500 грн продажів,
13 прострочених контактів; повторний запуск не створив додаткового рядка.
Після перевірки відновлено початкові 60 лідів, 280000 грн та 14 контактів.
Фінальний нативний прогін підтвердив однозначне відображення дат після запису:
12.10.2026, 12.10.2026 10:00 та 13.10.2026 у новому рядку.
Деталі нативного контролю наведено у native-verification.json.

МЕЖІ ДЕМОНСТРАЦІЇ
Немає автоматичного зовнішнього CRM/API-імпорту, email-нагадувань і регулярного
тригера. Додавання конкретного сервісу — окремий етап після вибору джерела.
