Поскольку внешние текстовые ссылки tvoymarketing.ru/manifest и tvoymarketing.ru/page149247586.html сейчас недоступны для прямого скачивания через парсер, я объединил все наши успешные архитектурные решения, сквозную логику ядра Balloon CRM, настройки безопасности и мультивалютности в один монолитный, исчерпывающий документ.
Ниже представлен Генеральный обновленный манифест платформы Balloon CRM v120.0.
📑 ГЕНЕРАЛЬНЫЙ МАНИФЕСТ И ТЕХНИЧЕСКАЯ ДОКУМЕНТАЦИЯ: BALLOON CRM v120.01. ГЛОБАЛЬНАЯ АРХИТЕКТУРА И ДВИЖЕНИЕ ДАННЫХ
Платформа Balloon CRM развернута на гибридной бессерверной архитектуре по модели Multi-Tenant (Изолированные БД клиентов) на базе инфраструктуры Google и интерфейсов Tilda.
  1. Мастер-Таблица Управления Платформой (Google Таблица «Админ»): Хранит лист Пользователи. Является единой точкой верификации доступов, ролей и сроков подписки.
  2. Изолированные БД пользователей: У каждого клиента CRM развернута персональная копия Google Таблицы (с листами Заказы, Товары, Настройки, Расходы), идентифицируемая по уникальному ключу sheet_id / sid.
  3. Фронтенд (Tilda, Блок T123): Single Page Application (SPA), обменивающееся данными с облаком через асинхронные JSONP и XHR POST шлюзы, полностью изолированные от дефолтных триггеров лидогенерации Tilda.
2. КАРТА РАЗМЕЩЕНИЯ КОДА И ФАЙЛОВАЯ СТРУКТУРА📁 ТОЧКА А. Фронтенд (Платформа Tilda)
  • Локация: Личный кабинет Tilda ➔ Редактор страницы CRM ➔ HTML-блок T123 (в самом подвале страницы).
  • Содержимое: Скрипты инициализации интерфейса, реактивные модули рендеринга таблиц, обработчики локального кэша сессий localStorage, динамический калькулятор стоимости заказов.
📁 ТОЧКА Б. Серверное ядро (Google Apps Script)
  • Локация: Меню мастер-таблицы ➔ РасширенияApps Script ➔ Файл проекта baza.gs (Развернут как веб-приложение с правами доступа «Все, даже анонимные»).
  • Содержимое: Маршрутизатор запросов doGet(e) и doPost(e), тяжелые функции дисковой записи, шлюзы авторизации, валидаторы подписок.
3. ДЕТАЛЬНОЕ ОПИСАНИЕ И АЛГОРИТМ РАБОТЫ ВСЕХ ФУНКЦИЙ🔐 МОДУЛЬ АВТОРИЗАЦИИ И ФОНОВОЙ БЕЗОПАСНОСТИ СЕССИЙfunction doPost(e) (Сценарий авторизации, ветка action === "login")
  • Где лежит: Файл baza.gs (строки 170–190).
  • Как работает: Проверяет совпадение логина и пароля по листу Пользователи мастер-таблицы. Внутрь интегрирован жесткий валидатор даты подписки (Столбец G, индекс 6). Если текущая дата больше даты в столбце G, скрипт мгновенно прерывает авторизацию и отдает на фронтенд ответ error: "subscription_expired". Внедрен обход пароля для фонового обновления сессий по sheet_id (если пароль пустой, но токен валидный — проверяется только срок действия подписки).
function doGet(e) (Центральный шлюз скачивания базы и фоновой защиты сессий)
  • Где лежит: Файл baza.gs (строка 311, прямо перед if (!sId)).
  • Как работает: Вызывается автоматически фронтендом при каждом запуске CRM или обновлении экрана.
  • Безопасность сессий: Перед тем как выгрузить данные клиенту, скрипт бежит циклом по двумерному массиву usersRange мастер-листа Пользователи. Он сверяет sheet_id со столбцом C (индекс 2). Найдя совпадение, он считывает дату окончания из столбца G (индекс 6). Если подписка просрочена (календарный день меньше сегодняшнего), выполнение функции doGet намертво прерывается. Вместо базы данных скрипт возвращает JSONP-ответ { success: false, error: "subscription_expired" }.
  • Фронтенд-блокиратор (Tilda, строки 365–379): Функция sendJsonRequest перехватывает этот ответ, тотально зачищает кэш браузера (localStorage.clear()), стирает рабочие контейнеры #app-interface и выводит модальный белый экран фатальной блокировки. Экран содержит динамическую ссылку на личную Google Таблицу клиента (база в безопасности), регламентный текст и кнопку быстрой связи с администратором в Telegram (https://t.me) с автоматически набранным текстом сообщения: «Добрый день, хочу продлить подписку СРМ».
📦 МОДУЛЬ УПРАВЛЕНИЯ ТОВАРАМИ И ОБНОВЛЕНИЯ ПРАЙС-ЛИСТАwindow.crmCatalogPushToGoogle(event)
  • Где лежит: Tilda, блок T123 (самый подвал JS-скриптов).
  • Как работает: Принимает аргумент события клика по зеленой кнопке «Сохранить изменения в таблицу». Через методы event.preventDefault() и event.stopPropagation() наглухо блокирует встроенные лид-перехватчики Tilda (защита от нежелательной перезагрузки страницы).
  • Изоляция полей: Считывает инпуты цен и наименований товаров строго внутри родительского контейнера #crmCatalogTreeContainer с помощью локального метода treeContainer.querySelectorAll('input'). Это исключило баг, при котором скрипт товаров залезал в открытые модальные окна заказов, ломая номера телефонов менеджеров в undefined и сбивая маску ввода (+7, 8). Сформированный пакет улетает по адресу константы GOOGLE_SCRIPT_URL асинхронным XHR POST методом. После успешного ответа сервера страница мягко перезагружается для сброса кэша ОЗУ.
doPost(e) (Сценарий перехвата каталога товаров)
  • Где лежит: Файл baza.gs (самый верх функции doPost, строки 565–575).
  • Как работает: Принимает сырой POST-поток application/x-www-form-urlencoded. Внутрь встроен автономный декодер параметров pairs[i].split('='), который вытаскивает action и параметры товаров напрямую из тела текстового пакета e.postData.contents, обходя ограничения движка Google V8. При обнаружении экшена save_catalog скрипт запускает запись ячеек и выполняет жесткий досрочный выход return ContentService....
  • Результат: Движок автоматической генерации лидов платформы, расположенный ниже по файлу (строка 688), физически не получает управления при сохранении прайса. Создание фантомных пустых строк заказов (с маской B + 6 цифр) при изменении цен ликвидировано раз и навсегда.
function coreSavePrices(sheetId, clientCatalog)
  • Где лежит: Файл baza.gs (самый подвал серверных скриптов).
  • Как работает: Принимает ID таблицы и текстовую JSON-строку каталога. Раскодирует её через цикл while (decodedString.indexOf('%') !== -1).
  • Безопасная перезапись ячеек: Функция полностью отказалась от разрушительного метода goodsSheet.clear(), который уничтожал сетку ячеек и на долю секунды ломал формулы ВПР в калькуляторе главной таблицы, вызывая ошибку #REF! и ложные срабатывания роботов интеграций. Вместо этого применен мягкий метод .clearContent(). Он очищает только текстовое содержимое первых двух столбцов, сохраняя ячейки живыми. Затем через .setValues() записывается новый прайс. Для столбца B (Цены) принудительно устанавливается числовой формат отображения копеек .setNumberFormat("0.00"), что гарантирует сохранение дробных чисел без округлений. Категории заново подсвечиваются желтым цветом (#ffff00).
💵 МОДУЛЬ МУЛЬТИВАЛЮТНОСТИ И ДРОБНЫХ ЧИСЕЛ (КОПЕЕК / ЦЕНТОВ)Исправление функции выгрузки данных doGet
  • Где лежит: Файл baza.gs (строка 502).
  • Что исправлено: Системный парсер выгрузки цен изменен со старого целого parseInt(rawPrice) на дробный parseFloat(rawPrice) || 0. Бэкенд перестал принудительно обрезать копейки и центы, начав отдавать на Tilda точные дробные значения (например, 0.50).
window.crmUpdateOrderCurrencyLabels и window.recalcDealTotal
  • Где лежит: Tilda, блок T123 (модуль расчетов калькулятора, строки 285, 922, 975–989).
  • Как работает после перехода на плоский прайс-лист (один Столбец B): Из функций полностью удалена старая ошибочная зависимость от несуществующих ключей price_eur / price_usd (которые после слияния столбцов в один выдавали undefined и ломали математику чека, аварийно сбрасывая его в рубли).
  • Переменная активной валюты cur на строке 285 принудительно переведена на чтение из единого глобального кэша кнопок валют: var cur = localStorage.getItem('crm_active_currency') || ....
  • Автоматический перехватчик дашборда стоимости заказа (строки 975–989): В подвал функции пересчета вшит автономный триггер вёрстки. При выполнении любого математического действия (добавление товара, ввод скидки, изменение доставки) скрипт вытаскивает активный знак валюты (symbols[cur]), рассчитывает итоги с точностью двух знаков после точки .toFixed(2), выводит их на зеленую плашку, а также на ходу переписывает текстовые заголовки инпутов на экране, превращая надписи ДОСТАВКА P и ПРЕДОПЛАТА P в динамические мультивалютные подписи ДОСТАВКА € или ПРЕДОПЛАТА €.
4. СВОДНАЯ ТАБЛИЦА РАЗМЕЩЕНИЯ КОМПОНЕНТОВ

Модуль системы

Файл / Место хранения (Где искать)

Строки / Селекторы

Основной системный метод

Фоновый чек подписок (Сессии)

Бэкенд: baza.gs

Строка 311 (внутри doGet)

usersRange[k][6] ➔ ContentService

Экран блокировки и ссылки

Фронтенд: Tilda (T123)

Строки 365–379 (sendJsonRequest)

document.createElement('div')

Перехватчик триггеров Tilda

Бэкенд: baza.gs

Самый верх doPost (565–575)

e.postData.contents.split('&')

Изолированный сбор прайса

Фронтенд: Tilda (T123)

Функция crmCatalogPushToGoogle

treeContainer.querySelectorAll('input')

Мягкое обновление прайса

Бэкенд: baza.gs

Функция coreSavePrices (подвал)

.clearContent() + .setNumberFormat("0.00")

Выгрузка дробных цен

Бэкенд: baza.gs

Строка 502 (внутри doGet)

`parseFloat(rawPrice)

Динамический знак чека и полей

Фронтенд: Tilda (T123)

Подвал window.recalcDealTotal

localStorage.getItem('crm_active_currency')

Все изменения внесены в строгом соответствии с ООП-стандартами JavaScript и архитектурными особенностями Google V8 Engine. Система полностью готова к работе.
Мы готовы переходить к следующей крупной задаче из вашего ТЗ! Берем в детальный разбор автоматическое обнуление дебиторской задолженности (остатка долга) на листе заказов, когда менеджер переводит сделку в отказной статус воронки продаж («Отказ» / «Не целевой»), или переходим к доработке календаря операционных расходов по месяцам-аккордеонам? Присылайте вводные!



Made on
Tilda