Поздравляю с успешным завершением этого масштабного и сложного этапа разработки! Мы полностью развязали узлы архитектурных конфликтов между Tilda и Google Apps Script, обеспечив стабильную работу SaaS-платформы Balloon CRM.
Ниже представлен детальный Манифест проекта со сквозным описанием всех внедренных обновлений, картой функций и схемой движения данных. Скопируйте этот документ в свой внутренний архив проекта или передайте другим разработчикам в качестве технической документации.


📑 МАНИФЕСТ ПРОЕКТА BALLOON CRM: МОДУЛЬ УПРАВЛЕНИЯ ТОВАРАМИ И ПРАЙС-ЛИСТОМ1. Архитектура Сетевого Моста и Передачи Данных
Платформа работает по модели изолированных баз данных (Tenant DB). У каждого пользователя CRM есть личная копия шаблона Google Таблицы. Идентификация пользователя на бэкенде происходит по динамическому ключу таблицы sheet_id (или sid), который фронтенд на Tilda извлекает из реактивной памяти страницы (window.st.sheet_id) или локального кэша браузера (localStorage).
Схема движения данных при сохранении прайса:
  1. Фронтенд (Tilda): Менеджер нажимает кнопку «Сохранить изменения в таблицу».
  2. Изоляция DOM-полей: Скрипт осуществляет изолированный сбор данных полей ввода строго внутри контейнера товаров, исключая пересечение с модальными окнами создания заказов.
  3. Сериализация: Данные прайс-листа приводятся к плоской текстовой структуре и упаковываются в валидную JSON-строку.
  4. Сетевой транспорт (XHR POST): Пакет параметров отправляется на единый бэкенд платформы методом POST через XMLHttpRequest с типом контента application/x-www-form-urlencoded. Адресация идет строго на глобальную константу GOOGLE_SCRIPT_URL, что гарантирует беспрепятственное прохождение сетевых шлюзов.
  5. Бэкенд (Google Apps Script): Главная функция doPost(e) на первой же миллисекунде перехватывает входящий пакет, раскодирует параметры, вызывает исполнительную функцию обновления ячеек и принудительно обрывает сессию с помощью return.
  6. Синхронизация ячеек: Данные записываются в Excel-таблицу конкретного пользователя. В случае успеха сервер возвращает фронтенду статус "success".
  7. Релоад фронтенда: Tilda принимает ответ от сети, снимает блокировку с кнопки сохранения и мягко перезагружает страницу, сбрасывая кэш браузера по регламенту SaaS.


2. Карта JavaScript Функций на стороне Tilda (Блок T123)window.crmRenderProductsTab()
  • Назначение: Основной реактивный метод отрисовки дерева прайс-листа на экране CRM.
  • Логика работы: Бежит циклом по массиву window.st.catalog. Если у объекта стоит флаг isGroup === true, он генерирует HTML-разметку желтой строки категории (Группы). Если флаг false — рендерит карточку товара с полями ввода наименования и цены.
  • Безопасность: Каждому отрендеренному инпуту на экране присваивается уникальный динамический ID вида id="prod-name-${index}" и id="prod-price-${index}". Это полностью защищает систему от смещения строк на экранах мобильных устройств.
window.crmCatalogAddItem(groupName)
  • Назначение: Добавление новой строки товара внутрь конкретной категории.
  • Логика работы: Принимает имя категории, принудительно очищает строку от эмодзи и пробелов методом replace(), находит точный индекс родительской группы сверху вниз и выполняет точечную вставку элемента через .splice(insertIndex, 0, newItem). Это исключает баг, при котором товары улетали в самый конец общего списка прайса.
window.crmCatalogMoveRow(index, dir)
  • Назначение: Интерактивное перемещение элементов прайс-листа вверх (▲) и вниз (▼).
  • Логика работы:
  • При перемещении ТОВАРА: меняет элементы местами в массиве, но жестко блокирует операцию, если товар пытается вылететь за границы своей родительской группы.
  • При перемещении ГРУППЫ: Скрипт отфильтровывает и собирает в единый пакет саму желтую строку категории и все входящие в неё товары. Затем этот пакет целиком «перепрыгивает» через соседнюю группу, сохраняя внутреннюю структуру каталога.
window.crmCatalogPushToGoogle(event)
  • Назначение: Сбор актуальных данных с экрана и отправка POST-пакета на сервер.
  • Логика работы: Принимает аргумент события клика event. С помощью event.preventDefault() и event.stopPropagation() намертво блокирует встроенные дефолтные триггеры Tilda (которые пытались отправить форму как лид-заявку). Считывает актуальные значения инпутов по их персональным id, приводит цены к числовому типу Number (валидация V8) и передает строку в XHR-шлюз.


3. Карта Серверных Функций в Google Apps Script (baza.gs)doPost(e)
  • Назначение: Главная точка входа для всех POST-запросов платформы.
  • Логика работы: В самом начале функции развернут изолированный перехватчик каталога. Он проверяет входящий параметр action. Если action === "save_catalog", скрипт забирает targetSid, передает каталог в исполнительную функцию и делает досрочный return ContentService.createTextOutput(...).
  • Результат: SaaS-код генерации лидов, расположенный ниже по файлу, физически не получает управления. Создание фантомных пустых заказов (с маской B + 6 цифр) при изменении цен полностью ликвидировано.
coreSavePrices(sheetId, clientCatalog)
  • Назначение: Физическая очистка и перезапись листа «Товары» в Google Таблице текущего пользователя.
  • Логика работы:
  • Принимает ID таблицы и строку каталога. Внутрь встроен цикл while (decodedString.indexOf('%') !== -1), который чисто раскодирует любые избыточные URL-проценты, присланные браузером.
  • Безопасная перезапись ячеек: Вместо разрушительного метода goodsSheet.clear() (который полностью уничтожал структуру ячеек и приводил к секундному падению формул ВПР в калькуляторе таблицы в ошибку #REF!), теперь используется метод .clearContent(). Он очищает только текстовое содержимое первых двух столбцов, сохраняя ячейки живыми. Это предотвратило ложные срабатывания внешних интеграций (Albato/Tilda вебхуков), которые реагировали на поломку формул созданием фантомных заказов.
  • Накладывает форматирование: заново находит строки групп и окрашивает их в ярко-желтый цвет (#ffff00), делая шрифт жирным.


4. Обновления HTML-Вёрстки (Tilda)
  • Исправление inline-стилей: Из самой первой строчки вкладки управления товарами (<div id="tab-products">) полностью удалено свойство style="display: none;". Это встроенное свойство намертво блокировало отображение, перебивая системный класс .active. Теперь вкладка подчиняется родной логике вкладок CRM.
  • Мобильная адаптивность: Внутрь HTML-шаблонов строк товаров и групп интегрированы флекс-контейнеры с автоматическим переносом элементов (display:flex; flex-wrap:wrap; gap:8px;). На экранах смартфонов поля названий, цен и кнопки управления больше не вылезают за границы экрана и не наезжают друг на друга.
  • Инструкция-баннер: На первую строчку панели товаров (строго над контейнером дерева) интегрирован информационный баннер со стильной иконкой 💡 и прямой кликабельной ссылкой на официальный регламент управления товарами в Google Docs. Ссылка открывается в новой вкладке (target="_blank"), не сбивая сессию менеджера.


Все узлы синхронизации завязаны в единую, отказоустойчивую систему!
Мы готовы двигаться дальше по бэклогу. Какую задачу берем в работу следующей: настроим автоматическое обнуление дебиторской задолженности (остатка долга) в таблице при переводе сделок в статус «Отказ» / «Не целевой», или переходим к модулю расходов по месяцам-аккордеонам?




Made on
Tilda