Схемы Что нового

Клиенты

Список клиентов и папки, поиск и карта подключений. Счета, финансовые операции, обещанный платёж и блокировки — на странице «Деньги клиента».

Клиенты — управление подключениями
Модуль «Биллинг-ядро» — на сайте продукта
Содержание раздела

Клиенты

Раздел меню «Клиенты» — основной рабочий раздел оператора.

Обучающее видео 2:50

Папка и глобальный поиск, счётчики-фильтры и цвет строки, одиннадцать массовых действий, создание клиента с учётной записью и IP, карточка клиента и карта.

1920×1080 с озвучкой Скачать

Папки клиентов — назначение и роль

Содержание раздела

Папка клиентов — это «контейнер-узел» в дереве клиентов с флагом IS_FOLDER=true. Хранится в той же таблице abonents (поле parent_id), но не имеет тарифа, счёта и финансовых атрибутов. Корневая папка имеет ID=9001.

Зачем нужны папки

Папки решают три задачи:

  1. Логическая группировка — клиенты раскладываются по агентам, филиалам, типам клиентов, географическим зонам. Это удобно для навигации и фильтрации в админке;
  2. Контроль доступа операторов — через AbonentGroupAccess Django-группа привязывается к конкретным папкам, и оператор видит только своих клиентов;
  3. Корзина удалённых — обычно это спец-папка (#9003 «Удалённые»), куда перемещаются deleted=true-клиенты для возможного восстановления.
Как устроено дерево

Иерархия держится на parent_id — FK таблицы на саму себя:

Поля lft / rght / tree_id / level не используйте. У новых записей они не заполняются: модель Abonents не подключена к MPTT-менеджеру, а значит rebuild() и get_descendants() недоступны. Код, который читает эти поля, обязан иметь fallback на parent_id — как это сделано в выборке клиентов по папкам (views/messages_global.py). Обход поддерева пишется обходом по уровням через parent_id.
Группы и контроль доступа

Связь «Группа Django ↔ Папка клиента» хранится в AbonentGroupAccess:

Папка организации

При включённой мультиорганизации папку верхнего уровня (лежащую внутри корневой «Все») можно закрепить за компанией — она становится её «домом»: туда складываются новые клиенты этой организации, и по ней строятся списки директорий в карточках тарифов.

Дерево папок: цвет иконки — акцентный цвет организации
Дерево папок: цвет иконки — акцентный цвет организации
Смена организации у папки — операция с данными, а не пометка. Она переписывает организацию у всего содержимого, включая финоперации клиентов. Отменить одним действием нельзя: обратный перенос — это повторное закрепление за прежней компанией.
Что делать со старыми папками
Важно про корзину: при Abonents.delete() в коде выполняется soft-delete: deleted=true + enabled=false, клиент остаётся на своём месте в дереве. Если хотите централизованную «Корзину» — настройте автоматическое перемещение в #9003 через bulk action или добавьте логику в delete() модели.

Клиенты

Главный список клиентов. Можно работать в двух режимах: дерево папок (по умолчанию) и глобальный поиск. Папки удобны для иерархической навигации по агентам/филиалам/адресам, глобальный поиск — для массовых операций над всей базой.

Папка клиентов

Папка клиентов (/admin/Abonents/<id>/, корень — /admin/Abonents/9001/) — список клиентов конкретной папки с поддержкой подпапок. Каждая папка имеет свой набор быстрых фильтров и массовых действий, рассчитанный на ежедневную работу оператора с одним сегментом базы.

Папка клиентов
Папка клиентов
Содержание раздела
KPI и статистика

Над таблицей выводятся 4–5 счётчиков по клиентам текущей папки (без учёта подпапок): Активных, Сейчас онлайн, Выключенных, Всего, Юр. лиц. Числа обновляются вместе с применённым фильтром-чипом.

Чипы быстрых фильтров

Под счётчиками — ряд чипов с готовыми фильтрами. Активен может быть только один. Повторный клик снимает фильтр. Состояние сохраняется в URL — ссылку можно отправить коллеге:

Колонки таблицы
  1. ☑ — чекбокс выбора для массовых операций.
  2. № — внутренний ID клиента.
  3. ФИО — клик открывает карточку.
  4. Дог. — номер договора.
  5. Тариф — с иконкой 💼 для бизнес-тарифов.
  6. Адрес — короткий формат (через фильтр home_short: ВО → Волгоградская обл., Влг → Волгоград).
  7. Контакты — иконки ✉ / 📞 с tooltip-значениями. Серая иконка = пустое поле.
  8. Баланс — баланс счёта. Рядом 🤝 при активном обещанном платеже.
  9. Подкл. — дата подключения.
  10. 📡 — флаг «онлайн сейчас» (RADIUS-сессия < 15 мин).
  11. Статус — цветной бейдж: Активен / Заблок. / Удалён.
  12. ℹ Подробнее — кнопка открывает drawer-панель без перехода на полную карточку.

Подсветка строк (класс строки задаётся в abonents_folder_rows.html):

Тумблер «Цвет маркер» над таблицей гасит подсветку целиком; выбор запоминается за оператором.

Бесконечная подгрузка

Папка не использует пагинацию. При прокрутке вниз автоматически догружается следующая порция (по 100 записей) через AJAX-endpoint /admin/Abonents/<id>/children_json/. На больших папках (1000+ клиентов) загрузка остаётся плавной — браузер рендерит только видимый кусок.

Массовые действия и экспорт

Чекбокс в первой колонке + «Выбрать все на странице» в шапке. После выделения появляется меню «Действия (N)» — те же 11 операций, что и в глобальном поиске: включить / выключить / удалить / изменить тариф / точку подключения / перенести в другую папку / добавить услугу / бонус / финоперацию / лояльность / отправить сообщение. Destructive-операции защищены confirm-модалкой с предпросмотром имён, для большинства — кнопка «Откатить» в баннере на 1 час.

Экспорт CSV — кнопка «📥 CSV» в шапке выгружает текущий срез папки (/admin/Abonents/<id>/export/): UTF-8 BOM, разделитель «;» для Excel RU. Колонки совпадают с видимыми в таблице плюс расшифровка тарифа, оператора, баланс в рублях. Учитываются текущий фильтр-чип и текстовый поиск.

Навигация по подпапкам

Если у текущей папки есть подпапки — они выводятся отдельным блоком над таблицей клиентов: карточки с именем подпапки и счётчиком клиентов внутри (включая глубоких потомков). Клик переходит в подпапку (отдельный URL). Хлебные крошки в шапке страницы показывают полный путь от корня (#9001 → город → улица → дом), кликабельны.

Мультиорганизация

Выбор организации в шапке — это фильтр отображения. Пока выбрана конкретная компания, раздел показывает только её данные:

Фильтр в шапке не даёт и не отнимает прав. Право на объект определяют организации сотрудника (изоляция персонала), а не текущий выбор в селекторе. Проверка доступа по прямой ссылке смотрит только на права: иначе при выбранной компании любой объект другой отдавал бы 404 — включая корневую папку клиентов, единственный вход в раздел. Ответ на действительно чужой объект — 404, одинаковый с «не существует», чтобы перебором нельзя было выяснить состав базы.

Модалка «Новый клиент»

Открывается зелёной кнопкой над деревом. Что важно знать при мульти-орг:

Модалка «Новый клиент» — выбор организации в шапке
Модалка «Новый клиент» — выбор организации в шапке
Раскладка новых клиентов

Куда попадёт клиент при создании, задаёт настройка Настройки → Система → Профиль → «Раскладка новых клиентов» (ABONENT_FOLDER_ROUTING):

РежимПоведение
По директории тарифа, иначе по организации значение по умолчанию: сначала папка тарифа, при её отсутствии — папка организации
Только по папке организации директория тарифа игнорируется
Не раскладывать клиент остаётся там, где его создают
Настройки → Система → Профиль → Раскладка новых клиентов
Настройки → Система → Профиль → Раскладка новых клиентов
flowchart TD
    ADD["Создание клиента"] --> WHERE{"Откуда добавляют"}
    WHERE -->|"из конкретной папки"| KEEP["Остаётся в ней"]
    WHERE -->|"из корневой Все"| MODE{"Режим раскладки"}
    MODE -->|"Не раскладывать"| ROOT["Остаётся в корне"]
    MODE -->|"Только организация"| ORG["Папка организации"]
    MODE -->|"По тарифу"| HAS{"У тарифа есть директория"}
    HAS -->|"да"| TAR["Папка тарифа"]
    HAS -->|"нет"| ORG
Выбор оператора не переопределяется. Раскладка работает только при создании из корневой папки «Все». Если оператор открыл конкретную папку и добавляет клиента там — это осознанное решение, и запись остаётся на месте в любом режиме.

Если папка тарифа принадлежит другой компании, организация клиента синхронизируется по папке: иначе он лежал бы в чужой папке со своей меткой и пропадал из неё при фильтре по организации. На практике случай редкий — тарифы уже отфильтрованы по организации, и чужой выбрать нельзя.

Глобальный поиск (Клиенты → 🔍 Глобальный поиск, URL /admin/Abonents/search/) — плоский список всех клиентов без иерархии папок, с расширенными фильтрами и массовыми операциями. Папки в выборку не попадают (is_folder=false).

Раздел рассчитан на сценарии, когда нужно работать со всей базой сразу: найти клиента по обрывку информации (часть телефона, дома, фамилии), сделать массовую рассылку по тарифу, выгрузить срез для бухгалтерии.

Глобальный поиск клиентов
Глобальный поиск клиентов
Содержание раздела
KPI-бейджи в шапке

Над таблицей выводится 4 счётчика по результатам текущей выборки: Активных (enabled=true) / Сейчас онлайн (RADIUS-сессия < 15 мин) / Выкл (enabled=false) / Всего. Цифры пересчитываются на каждой смене фильтра.

Чипы быстрых фильтров (7 штук)

Чипы взаимоисключающие — активен может быть только один. Кликом по уже активному чипу фильтр сбрасывается. Состояние записывается в URL (?chip=debtors) — ссылку можно отправить коллеге.

ЧипИконкаЧто показываетSQL-условие
Должники⚠ Клиенты с отрицательным балансом счёта admin_account.ostatok < 0
Бизнес💼 Юридические лица abonents.company = true
Без email✉ Не указан e-mail для уведомлений email IS NULL OR email = ''
Без телефона📵 Не указан номер телефона (SMS не уйдут) sms IS NULL OR sms = ''
Онлайн📡 Сейчас в RADIUS-сессии (< 15 минут с last update) USERS_RADIUSAUTH.LOGGED = 1 AND RADIUS_UPDATE >= now() - 15 min
Заблокированные🚫 Любая активная блокировка (admin / negbal / own) есть запись в ABONENTS_BLOCK с активным флагом
Обещ. платёж🤝 Активен обещанный платёж (Usluga 30353) users_usluga.usluga_id = 30353 AND enabled = true
Multi-select фильтры
Текстовый поиск

Поле в шапке таблицы. Серверный поиск по: ФИО, номер договора, e-mail, телефон, адрес (город / улица / дом / квартира). Минимум 2 символа, debounce 300 мс. Шорткат Ctrl+K ставит фокус в поле поиска из любого места страницы.

Колонки таблицы (12)
  1. ☑ — чекбокс выбора для bulk-операций.
  2. № — внутренний ID клиента.
  3. ФИО — имя, кликабельно (открывает карточку).
  4. Дог. — номер договора.
  5. Тариф — название текущего тарифа; для бизнес-тарифов иконка 💼.
  6. Адрес — короткий формат через фильтр home_short (ВО → Волгоградская обл., Влг → Волгоград, район сокращённо).
  7. Точка подкл. — название ConnectionPoint.
  8. Контакты — иконки ✉ / 📞 с tooltip-значениями. Серая иконка = не заполнено.
  9. Баланс — баланс счёта; рядом 🤝 при активном ОП.
  10. Подкл. — дата подключения.
  11. 📡 — флаг «онлайн сейчас» (RADIUS-сессия < 15 мин).
  12. Статус — цветной бейдж (Активен / Заблок. / Удалён).

Подсветка строк — та же, что в папке: розовый фон — блокировка за неуплату, жёлтый — другая блокировка, красный — выключен, усиленный красноватый — долг более 500 ₽. Разбор классов — в описании папки.

Бесконечный скролл

Глобальный поиск не использует пагинацию: при прокрутке вниз подгружается следующая порция результатов. Папочные страницы (/admin/Abonents/<id>/) работают по тому же принципу через AJAX-endpoint /admin/Abonents/<id>/children_json/ по 100 записей за запрос.

Массовые действия — 11 операций

Выбираете клиентов галочками в первой колонке (или «Выбрать все» в шапке) — в шапке появляется выпадающее меню «Действия (N)» с дюжиной операций. Endpoint: POST /admin/Abonents/bulk_action/ (payload: action + ids[] + параметры).

ДействиеЧто делаетUndo
Включить (enable) Снимает флаг enabled=false, шлёт CoA-Disconnect для переподключения. ✅
Выключить (disable) Ставит enabled=false, разрывает RADIUS-сессии. ✅
Удалить (delete) Soft-delete: deleted=true, все Users отключаются, CoA-Disconnect. ✅
Изменить тариф (change_tarif) Смена тарифа в окне выбора. Срабатывает сразу, не «с 1-го числа». ✅
Изменить точку подключения (change_cp) Перевешивает клиента на другую ConnectionPoint. —
Перенести в папку (move_folder) Меняет parent_id в MPTT-дереве (выбор папки из списка). ✅
Добавить услугу (add_service) Подключает разовую/периодическую услугу (услуга из списка). —
Добавить бонус (add_bonus) Подключает бонус (компенсация / скидка с отрицательной суммой). —
Добавить операцию (add_finop) Создаёт FinanceOperations на счёт (тип, сумма, описание). —
Добавить лояльность (add_loyalty) Включает программу лояльности (AbonentsLoyalty). —
Отправить сообщение (send_msg) Рассылка по выбранным каналам: e-mail / SMS / Push / Telegram. —

Для destructive-операций (Включить / Выключить / Удалить / Изменить тариф / Перенести в папку) после выполнения в шапке появляется баннер «Откатить (доступно N мин)» с таймером 1 час. Клик отменяет изменение для всех затронутых клиентов через POST /admin/Abonents/bulk_undo/. Undo-токен хранится в sessionStorage браузера. Create-операции (Добавить услугу / бонус / финоперацию / лояльность / отправить сообщение) не откатываются — придётся вручную удалять созданные записи.

Подтверждение опасных операций

Удаление, отключение, включение и смена тарифа открывают модальное окно подтверждения: показывает превью первых 5 имён выбранных клиентов, общее их количество и требует ввести точное число выбранных записей для активации кнопки «Подтвердить». Это защита от случайной массовой операции по невнимательности.

CSV-экспорт

Кнопка «📥 CSV» в шапке выгружает текущий видимый срез (/admin/Abonents/search/export/): UTF-8 BOM, разделитель «;» для Excel RU. Колонки те же что в таблице плюс расшифровка тарифа, оператор и баланс в рублях.

Слайд-панель клиента (drawer)

В строках таблиц списков клиентов (папка, глобальный поиск, должники) у каждой записи справа есть кнопка ℹ Подробнее (на mobile — клик по имени). Клик открывает выезжающую справа панель (slide-panel / drawer) с краткой сводкой по клиенту — без ухода со списка и потери контекста (фильтры, прокрутка, выделение сохраняются).

Панель решает задачу «быстро глянуть и сделать», когда полная карточка с десятком вкладок избыточна. Типичные сценарии за 5–30 секунд: проверить баланс и активировать ОП, посмотреть статус сессии при жалобе на интернет, отправить SMS-напоминание, добавить комментарий-заметку для коллег.

Слайд-панель клиента — общий вид при открытии
Слайд-панель клиента — общий вид при открытии
Содержание раздела
Где доступна панель

Программный API из любой страницы: window.AbDrawer.open(abonentId).

Шапка с плашками статуса

Вверху панели — компактные плашки с ключевыми атрибутами клиента (видно с одного взгляда, без скролла):

ПлашкаЧто показываетЦвет
#<номер договора>Номер договора клиента—
Активен / ОтключёнСостояние клиента целикомзелёный / жёлтый
Физ. лицо / БизнесТип клиентасерый
🔑 ЛогинОсновной логин учётной записи (скрыт на mobile)серый
🌐 IPIP-адрес учётной записисерый
🔓 Вкл. / 🔒 Выкл.Состояние учётной записи (отдельно от клиента)зелёный / жёлтый
📶 Онлайн / 🔌 ОфлайнСейчас в RADIUS-сессии или нетзелёный / жёлтый
🪪 СОРМ N/9Полнота персональных данных по СОРМ-требованиямзелёный (9/9) / жёлтый (5–8) / красный (0–4)

Шапка имеет фон заметно темнее тела (light #e8edf2 / dark #14171b) — оператор сразу различает «где статус, где данные».

Финансовый KPI-блок

Сразу под шапкой — KPI-сетка 2×2 с самыми важными цифрами:

Если активен обещанный платёж — отдельная плашка с суммой и датой окончания под KPI-сеткой.

Аккордеон разделов и smart-defaults

Разделы панели объединены в аккордеон — оператор сам открывает что нужно, не скроллит мимо. Состояние свёрнутости запоминается в localStorage отдельно по каждой секции — выбор оператора сохраняется.

РазделSmart-default (открыт если…)
👤 Учётные записиУчётка отключена (!primary_enabled) — оператор сразу видит проблему
🌐 Последняя сессияКлиент онлайн или есть активная сессия
📈 Платежи за 12 мес.Всегда свёрнут — открывается по запросу
📋 Последние операцииДолжник (balance < 0) — оператор смотрит откуда долг
🏛 БанкРаздел показывается только при наличии хотя бы одного платежа из банковских выписок; открывается смотря по контексту вызова
📝 Комментарии операторовУже есть комментарии — значит история важна
🎧 ПоддержкаКлиент ждёт ответа в HelpDesk (waiting_for_us > 0)

Раздел «Банк» показывает последние платежи клиента из банковских выписок (банк, дата, сумма, плательщик). При открытии панели кликом по имени клиента в очереди чеков («Очередь чеков») панель автоматически прокручивается к разделу «Банк» и раскрывает его — оператор сразу видит, откуда пришёл платёж по разбираемой операции.

Слайд-панель клиента — раздел «Банк» раскрыт, показан платёж из выписки Сбербанка
Слайд-панель клиента — раздел «Банк» раскрыт, показан платёж из выписки Сбербанка
Сброс сессии из блока «Последняя сессия»

Если у клиента есть активная RADIUS-сессия, в блоке «Последняя сессия» рядом с бейджем «Активная сессия» появляется кнопка «🔄 Сброс сессии». Она нужна при зависшей сессии (NAS не прислал Accounting-Stop, клиент «висит онлайн», но интернета нет).

Слайд-панель — блок «Последняя сессия» с кнопкой «Сброс сессии» и окном подтверждения
Слайд-панель — блок «Последняя сессия» с кнопкой «Сброс сессии» и модалкой подтверждения

Если оператор однажды раскрыл/свернул секцию вручную — это его выбор сохраняется в localStorage и smart-defaults больше не перетирают.

Слайд-панель — все разделы аккордеона раскрыты
Слайд-панель — все разделы аккордеона раскрыты
Раздел «Поддержка» (HelpDesk)

Шестой раздел аккордеона — интеграция с HelpDesk. Биллинг показывает все обращения клиента в техподдержку прямо в слайд-панели, без перехода в HelpDesk:

Слайд-панель — раздел «Поддержка» с обращением клиента
Слайд-панель — раздел Поддержка с тикетами HelpDesk

Форма отправки сообщений и табы каналов прилеплены ко дну панели (не уезжают при скролле истории сообщений). Оператор не скроллит чтобы написать SMS — форма всегда на виду, как в современных мессенджерах.

Форма отправки прилеплена ко дну панели при прокрутке
Sticky footer — форма отправки прилеплена ко дну при скролле
Каналы отправки (SMS / Email / Telegram / ЛК / ВК / Push)

Над формой ввода — chip-табы с каналами отправки. Показываются только доступные клиенту каналы:

При выборе таба Email над формой появляется поле «Тема письма» — если оператор не укажет, дефолтная тема возьмётся из первой строки текста (до 80 символов).

Табы каналов — выбран Email, появилось поле Тема письма
Табы каналов — выбран Email, появилось поле Тема письма

SMS-форма поддерживает дефолтный шаблон: при пустом тексте у должника автоматически отправляется напоминание «Договор XXX. Задолженность YYY ₽. После пополнения счёта доступ к услугам восстановится. Узнать баланс или взять ОП — отправьте «Баланс» или «Оп» в ответ на это сообщение. ЛК: lk.вашдомен.ru».

Для клиентов с положительным балансом дефолтный шаблон не отправляется — backend возвращает ошибку no_text_positive_balance, оператор должен ввести текст вручную.

Email в фирменном брендинге

Email-сообщения отправляются HTML в фирменном стиле — не plain text, а полноценное письмо с шаблоном emails/generic.html:

Авто-детект шаблона по теме/тексту: если содержит «обещанн», «оплат», «блокир», «возобновл», «баланс+низк» — выбирается специализированный пресет (promise_pay/payment_received/blocked/ unblocked/low_balance), иначе generic.

Доступность (WCAG colour independence)

Все цветовые статусы дублируются иконками — пользователи с deuteranopia (8% мужчин) различают информацию без полагания на цвет:

Mobile-режим

На телефоне (≤768px) панель раскрывается на весь экран (width: 100vw, height: 100dvh, без скруглений и отступа сверху) — не узкая шторка сбоку и не нижний лист, а полноэкранная слайд-панель, как модалки в мобильной версии проекта. Поведение одинаковое с desktop, только:

Слайд-панель на телефоне — на весь экран, форма отправки внизу
Слайд-панель на mobile — fullscreen с sticky footer
Тёмная тема

Drawer полностью адаптирован под тёмную тему. Header ещё темнее тела (#14171b vs body #1f2227), все секции и формы имеют тёмные варианты, footer-actions с своим bg.

Карточка клиента

Переход кликом по строке клиента — открывается отдельная страница с вкладками Информация, История, Тариф и услуги, Бонусы, Финансы, Точки подключения, Учётные записи, RADIUS, СОРМ, Реквизиты, HelpDesk, Лояльность. Подробное описание каждой вкладки — в отдельном разделе Карточка клиента.

Bulk-операции и Undo

Выберите клиентов галочками — появится плавающая панель действий внизу экрана.

Групповые действия: выбраны три клиента, открыто меню «Действия»
Bulk-операции с клиентами

Доступные действия:

Для destructive-операций (delete, disable, enable, change_tarif, move_folder) после выполнения в шапке появляется баннер «Откатить (доступно N мин)» с таймером 1 час. Клик отменяет изменение для всех затронутых клиентов.

На карте

Карта клиентов в браузере (Leaflet + OSM / 2ГИС / Yandex). Каждый маркер — клиент; отдельно показываются NAS и слой заявок Поддержки. URL: /admin/abonents/map/. Меню сайдбара: Клиенты → 🗺 На карте.

Карта клиентов — общий вид со слоями и легендой
Карта клиентов — общий вид со слоями и легендой
- "На карте"
  - Слои
    - Клиенты
      - Кластеры по плотности
      - Цвет = статус
    - NAS
      - Покрытие
      - Онлайн-панель
    - Заявки Поддержки
  - Фильтры
    - Статусы
    - Услуги
    - Поиск Ctrl+K
  - Данные
    - Только точные координаты
    - Скоуп по организации
    - Кеш 5 минут
  - Действия
    - Попап клиента
    - Карточка заявки
    - Правка координат

Возможности

Попап клиента: NAS-ссылка, организация, услуги
Popup клиента: NAS-ссылка, org-лейбл, услуги

Откуда берутся точки

Карта не запрашивает данные при каждом движении — весь набор приходит одним JSON и живёт в памяти вкладки. Отсюда два следствия: панорамирование мгновенное, но состав точек фиксируется в момент загрузки.

flowchart LR
    REQ["Открытие карты"] --> CACHE{"Кеш 5 минут
по организации"} CACHE -->|"есть"| JSON["JSON одним ответом"] CACHE -->|"нет"| HOMES["Адреса с координатами
qc_geo пусто или ≤ 1"] HOMES --> SCOPE["Скоуп по организации
клиента"] SCOPE --> BATCH["Батч-запросы:
NAS, блокировки, услуги"] BATCH --> JSON JSON --> RENDER["Кластеры на карте"]
Фильтр качества адреса. На карту попадают только адреса с qc_geo ≤ 1 — «точно дом» или «улица». Адреса, которые геокодер свёл к центру города (qc_geo ≥ 2), исключены: иначе сотни клиентов слиплись бы в одну точку и карта потеряла бы смысл.

Мультиорганизация

Точки, оборудование и заявки скоупятся по организации клиента. Важная деталь реализации: кеш партиционирован — ключ включает выбранную в шапке организацию и список доступных сотруднику компаний. Без этого первый открывший карту наполнил бы общий кеш своими данными, и остальные увидели бы чужих клиентов.

Если у организации нет ни одного адреса с точными координатами, карта не молчит, а объясняет причину и ведёт в редактор координат:

Пустая карта с объяснением причины
Пустая карта с объяснением причины

Сайдбар «Клиенты на NAS»

Клик по NAS-маркеру (кнопка «Клиенты») или по NAS-ссылке в попапе клиента открывает слайд-панель справа со списком клиентов выбранного NAS. Фильтр-чипы Все / Online / Offline со счётчиками, поиск (ФИО / логин / договор / IP), бесконечная прокрутка. Каждая строка — кликабельна (→ карточка клиента) и показывает: ФИО, бейдж «Заблок.» при блокировке, логин·IP, тариф, баланс (цветной ↑/↓) и иконки услуг.

Сайдбар клиентов NAS: тариф, баланс, услуги
Сайдбар клиентов NAS: тариф, баланс, услуги

Поток: маркер → попап → карточка / сайдбар

flowchart LR
    DATA["/admin/abonents/map/data/
points + NAS + заявки"] --> MAP["Карта Leaflet
кластеры"] MAP --> ABM(("Маркер
клиента")) MAP --> NASM(("Маркер
NAS")) MAP --> TKT(("Маркер
заявки")) ABM --> POP["Popup клиента
org · NAS · услуги"] POP -->|"ФИО"| DRAWER["Карточка клиента
→ блок «Услуги»"] POP -->|"Позвонить / E-mail"| DRAWERM["Карточка клиента
→ сообщения"] POP -->|"NAS-ссылка"| PANEL["Сайдбар «Клиенты NAS»
Все / Online / Offline"] NASM -->|"«Клиенты»"| PANEL PANEL -->|"строка"| DRAWER TKT --> TICKET["Карточка тикета
Поддержка СмИТ"] style DATA fill:#1e3a5f,stroke:#5BA89D,color:#fff style MAP fill:#134e4a,stroke:#43b77a,color:#fff style POP fill:#1e3a5f,stroke:#5BA89D,color:#fff style PANEL fill:#43b77a,stroke:#2d9a5f,color:#fff style DRAWER fill:#43b77a,stroke:#2d9a5f,color:#fff style DRAWERM fill:#14532d,stroke:#16a34a,color:#fff style TICKET fill:#78350f,stroke:#d97706,color:#fff

Тёмная тема и мобильный вид

Попап и сайдбар NAS полностью адаптированы под тёмную тему (контраст лейблов/значений ≥ WCAG AA). На мобильном панель фильтров — bottom-sheet.

Карта на телефоне — поиск и фильтры свёрнуты в одну строку
Карта на телефоне — поиск и фильтры свёрнуты в одну строку

Попап клиента

Клик по маркеру открывает карточку: договор, организация, NAS, тариф, адрес, баланс, точка подключения и значки подключённых услуг. Кнопки ведут в карточку клиента, звонок и почту — из карты можно начать работу, не открывая список.

Попап клиента на карте
Попап клиента на карте

Маркеры заявок открывают карточку тикета Поддержки в правой панели: история обращений, расшифровка звонка, приоритет и поле ответа. Снимки из переписки листаются просмотрщиком прямо в панели, у файлов виден значок своего формата, а прошлые обращения клиента открываются здесь же — со стрелкой возврата. Панель общая с картой сети, подробности там.

Карточка заявки Поддержки с карты
Карточка заявки Поддержки с карты

Вес карты и скорость

Карта — самый тяжёлый JSON в системе: несколько тысяч точек одним ответом. Две правки изменили порядок величины:

ЧтоБылоСтало
Передача по сети4585 КБ380 КБ
Размер JSON4584 КБ2750 КБ
Загрузка страницы11,6 с2,6 с

Геокодирование адресов

Чтобы клиент появился на карте, его адрес (Homes.parent_id) должен иметь координаты lat и lon. Заполнение координат происходит автоматически через геокодеры — внешние сервисы, которые по строке адреса возвращают координаты.

Поддерживаются два провайдера:

ПровайдерГде настроитьЛимитыКоманда
DaData (рекомендуется для России) /admin/settings/integrations/?tab=geo → «Адреса», поле DADATA_TOKEN. 10 000 запросов/день бесплатно (тариф «Бесплатный»), но не более 10 тыс. в месяц. manage.py geocode_homes_dadata [--re-geocode]
Яндекс.Геокодер (запасной) /admin/settings/integrations/?tab=geo → «Адреса», поле YANDEX_GEOCODER_API_KEY. 25 000 запросов/день бесплатно (HTTP Геокодер). manage.py geocode_homes_yandex [--re-geocode] [--only-no-qc]

API-токены задаются в разделе «Настройки → Интеграции → География» (вкладка «География → Адреса»). Здесь же есть кнопка «Проверить» для теста подключения и счётчик геокодированных адресов.

Кто может править координаты. Сдвинутая точка дома уводит с карты всех его клиентов, поэтому правка адресного справочника доступна суперпользователю и группам из настройки ADDRESS_ADMIN_GROUPS (по умолчанию root, address). Остальным сотрудникам сохранение вернёт 403.
Запуск геокодирования

На рабочий сервер сейчас геокодировано ~95% адресов (4045 из 4261), из активных клиентов ~90% на карте. Чтобы геокодировать новый адрес автоматически — введите его в форме клиента, и при следующем прогоне команды (или nightly Celery-задаче) он попадёт на карту. Запустить геокодирование вручную:

docker compose exec web python manage.py geocode_homes_dadata
# или принудительно для всех (включая уже геокодированные):
docker compose exec web python manage.py geocode_homes_dadata --re-geocode

Команда:

Маркеры клиентов на адресах с qc_geo=2 (только город) на карте отображаются как «приблизительные» — несколько клиентов одного города могут лечь на одну точку. Для повышения точности проверьте, что у адреса заполнены поля «Улица» и «Дом».

Reverse-геокодинг (заполнение города/района по координатам)

Если у адреса есть координаты, но не заполнен город или район (после миграции из старых биллингов это бывает), используйте команду manage.py enrich_homes — она через Яндекс.Геокодер (обратное направление: координаты → адрес) восстанавливает текстовые поля.

Тайловый слой (фон карты)

Подложка выбирается на той же вкладке «География» и применяется сразу ко всем картам панели: OpenStreetMap (по умолчанию, без ключа), CARTO (ключ выдаёт сервер лицензий), 2ГИС и Яндекс.Карты (свой ключ). В тёмной теме интерфейса карта тоже становится тёмной, а если провайдер перестал отдавать тайлы — подложка сама переключается на OpenStreetMap, чтобы карта не осталась пустой. Сотрудник может выбрать провайдера лично в Профиле. Подробнее — Подложка карт: провайдер, тёмная тема, ключ CARTO. Стиль карточки в /admin/settings/integrations/?tab=geo показывает количество геокодированных адресов и точность (% домов с qc_geo=0).