Отчёты
Готовые и произвольные отчёты, аудит операций, журналы платежей и сообщений, должники. Здесь же — раздел геймификации.
Содержание раздела
- 4. Отчёты
- 4.0. Панель директора
- Пользовательские SQL-отчёты — назначение и роль
- 4.1. Библиотека отчётов
- 4.2. Аудит
- 4.3. Журнал платежей
- 4.3.1. Очередь чеков (54-ФЗ)
- 4.4. Журнал сообщений
- 4.5. Разработка и логи
- 4.6. Должники
- 4.7. Миграция с других биллингов
- FrameworkFormGroupFields — назначение и роль
- 4.8. Настройки интерфейса (формы)
- 5. Игры (Маркетинг)
- 5.2. Настройки модуля «Маркетинг»
- 5.3. «Игра месяца» — бесплатный интернет
- 5.4. Условия участия в турнире
- 5.5. Вкладка «Маркетинг» в карточке клиента
- 5.6. Профиль-меню и мобильное приложение
4. Отчёты
Раздел меню «Отчёты» объединяет аналитику для руководителя, библиотеку SQL-отчётов, аудит действий персонала и журналы.
4.0. Панель директора
Содержание раздела
Панель директора (/admin/reports/dashboard/, сайдбар «Отчёты → Панель директора») отвечает на четыре вопроса о бизнесе за выбранный период: сколько денег пришло, сколько в среднем приносит клиент, сколько людей подключилось и сколько заблокировано. Ниже — шесть графиков по тем же данным в динамике.
Карта раздела
- Панель директора
- Показатели
- Выручка за период
- ARPU
- Новые клиенты
- Заблокировано за период
- Графики
- Популярность тарифов
- Новые клиенты
- Поступающие средства
- Платящие клиенты
- ARPU по месяцам
- ARPPU по месяцам
- Срезы
- Период и пресеты
- Сегмент физ-юр
- Канал оплаты
- Тариф
- Точка подключения
- Шаг день-неделя-месяц
- Сравнение с прошлым или годом назад
- Правила
- Данные своей организации
- Клик по показателю ведёт в список
- Ошибка отличается от пустоты
Четыре показателя и как они считаются
Формулы важнее оформления: по этим цифрам принимают решения, поэтому каждая должна читаться однозначно.
| Показатель | Что именно считается | Сравнение |
|---|---|---|
| Выручка за период | Сумма приходных финансовых операций (OP_SUMMA > 0) с датой внутри периода. Верхняя граница берётся включительно, до 23:59:59 последнего дня. |
к предыдущему периоду такой же длины |
| ARPU | Выручка периода ÷ база клиентов на конец периода (не удалённые, заведённые до этой даты). У прошлого периода — свой знаменатель, поэтому дельта ARPU не повторяет дельту выручки. | к тому же показателю прошлого периода |
| Новых клиентов | Клиенты с датой создания внутри периода. | к предыдущему периоду |
| Заблокировано за период | Клиенты, у которых блокировка началась внутри периода (ABONENTS_BLOCK.B_DATE). В подписи — сколько из них за неоплату и сколько клиентов активно сейчас. Рост показан красным: блокировок больше — это плохая новость. |
к предыдущему периоду |
Шесть графиков
| График | Что показывает |
|---|---|
| Популярность тарифов | Распределение клиентов по тарифам (без заблокированных). Хвост сворачивается в «Прочие». |
| Новые клиенты | Сколько подключилось в каждом периоде. |
| Поступающие средства | Приход по периодам — та же выручка в динамике. |
| Платящие клиенты | Сколько разных клиентов платили в периоде. |
| ARPU | Выручка периода ÷ база клиентов на его конец. |
| ARPPU | Выручка периода ÷ число заплативших — средний чек платящего. |
Если данных за период нет, карточка так и говорит: «За выбранный период данных нет». Если запрос не выполнился — это отдельное сообщение «Не удалось загрузить» с кнопкой «Повторить», чтобы сбой сервера не выглядел как «в этом месяце ничего не было».
Период и фильтры
Слева — выбор периода с пресетами (текущий месяц, прошлый месяц, квартал, год, всё время). Рядом кнопка «Фильтры» со счётчиком активных срезов:
| Фильтр | Значения | Зачем |
|---|---|---|
| Сегмент | Все · Физлица · Юрлица | У юрлиц другой чек и другая сезонность — смешивать их с частниками бессмысленно |
| Канал оплаты | типы приходных операций | Видно, через что реально идут деньги |
| Тариф | мультивыбор, рядом число клиентов | Как живёт конкретный тариф или линейка |
| Точка подключения | мультивыбор по населённым пунктам | Срез по географии: посёлок, СНТ, город |
| Шаг графиков | Месяц · Неделя · День | Дневной шаг показывает всплески внутри месяца |
| Сравнивать с | предыдущим периодом · тем же периодом год назад | Годовое сравнение снимает сезонность |
Выбранный набор сохраняется между заходами, сбрасывается ссылкой «Сбросить фильтры». Списки тарифов и точек показывают количество клиентов — выбирать можно осознанно.
CONNECTION_POINTS, названным по населённому пункту. Клиенты без точки в такой срез не попадают, поэтому под фильтром показано, скольких это касается. Массово назначить точки по адресу помогает команда manage.py assign_connection_points (с предпросмотром и откатом).
Откуда берутся цифры
flowchart LR
FO["Финансовые операции
finance_operations"] --> REV["Выручка
Поступающие средства"]
FO --> PAY["Платящие клиенты
ARPPU"]
AB["Клиенты
abonents"] --> BASE["База клиентов"]
BASE --> ARPU["ARPU"]
REV --> ARPU
AB --> NEW["Новые клиенты"]
AB --> TAR["Популярность тарифов"]
BL["Блокировки
ABONENTS_BLOCK"] --> BLK["Заблокировано
за период"]
ORG["Организация"] -.->|"фильтр"| FO
ORG -.->|"фильтр"| AB
ORG -.->|"фильтр"| BL
Теперь все шесть считаются из финансовых операций и карточек клиентов, то есть из тех же данных, что и KPI.
Мульти-организации
Панель показывает данные той организации, которая выбрана в шапке. Если выбрана конкретная компания, её название выводится бейджем справа в строке фильтров — чтобы не спутать, чьи цифры на экране. В режиме «Все организации» сотрудник видит только те компании, к которым у него есть доступ.
Фильтрация применяется ко всем шести графикам и ко всем четырём показателям, а также к спискам тарифов и точек в самих фильтрах: под чужую организацию не попадут ни её тарифы, ни её посёлки.
Переход к деталям
Под показателями есть ссылки в соответствующие разделы: «Платежи за период» открывает журнал платежей с теми же датами, «Кто подключился» — список клиентов по дате создания, «Список заблокированных» — глобальный поиск с чипом «Заблокированные». Увидев просадку, можно сразу посмотреть, из чего она сложилась.
Тёмная тема и телефон
Графики перерисовываются вместе со сменой темы, перезагрузка не нужна. На телефоне показатели встают в две колонки, фильтры — в одну, горизонтальной прокрутки нет.
Пользовательские SQL-отчёты — назначение и роль
Содержание раздела
AdminCustomReports — таблица сохранённых SQL-запросов, доступных оператору через UI. Каждая запись = один отчёт с именем, описанием и SQL-кодом. Хранится в таблице ADMIN_CUSTOM_REPORTS, редактируется на /admin/reports/AdminCustomReports/.
Зачем нужны кастомные отчёты
Биллинг — это система с ~150 таблицами и 600+ полей. Готовых отчётов в админке всегда не хватает: бухгалтер хочет один формат, директор — другой, техподдержка — третий. Решение:
- Гибкость без релизов — оператор-аналитик пишет SQL прямо через UI, без ожидания deployment'а;
- Параметризация — встроенный синтаксис
:Имя|тип$позволяет добавлять параметры (даты, клиент, сумма) без знания Python; - Экспорт — результат отчёта сразу в Excel/CSV/DBF без программирования;
- Историческая часть — каждый запуск сохраняется в
AdminCustomReportsHistory, можно вернуться к старому результату.
Поля и связанные таблицы
Поле ADMIN_CUSTOM_REPORTS | Назначение |
|---|---|
NAME | Название отчёта (видно в UI) |
DESCRIPTION | Описание для оператора (что отчёт показывает) |
REPORT_TEMPLATE | SQL-код запроса (text) |
REPORT_TYPE | FK на AdminCustomReportsType — категория |
ALLOW_IN_CABINET | Видим ли клиенту в ЛК (раздел «Мои отчёты») |
TECH_ADMIN / FIN_ADMIN / FULL_ADMIN / CARD_ADMIN / READ_ADMIN | Матрица прав по ролям оператора (1 = доступно) |
Связанные таблицы:
AdminCustomReportsType— справочник типов (см. ниже);AdminCustomReportsHistory— история запусков (user_id, params JSON, row_count, execution_time, sql_hash);report_executions— текущие выполнения (для предотвращения двойного запуска);report_favorites— закладки оператора (звёздочки).
Параметры в SQL — синтаксис
Внутри SQL можно использовать спец-плейсхолдеры в формате :Имя|тип$ или :Имя|тип[аргументы]$. Когда оператор запускает отчёт — UI генерирует форму с этими параметрами, подставляет значения и выполняет SQL.
| Тип | Пример SQL | UI |
|---|---|---|
date | WHERE op_date >= :Начало|date$ | Date-picker |
sum | WHERE op_summa > :Минимум|sum$ | Поле для рублей с конвертацией ×10^10 |
select[Model] | WHERE abonent_id = :Клиент|select[Abonents]$ | Select2-AJAX по модели |
choices[1^Янв|2^Фев|3^Мар] | WHERE month = :Месяц|choices[1^Январь|2^Февраль]$ | Dropdown с фиксированными значениями |
Парсинг — regex в AdminCustomReports._get_sql_fields(), подстановка в _execute_sql() с защитой от SQL-injection.
Типы отчётов
Справочник ADMIN_CUSTOM_REPORTS_TYPE — 7 категорий с цветными бейджами:
- 🛠 Техсервис — для техников (NAS, RADIUS, оборудование)
- 📈 Руководство — KPI, статистика, тренды
- ⛑ Техподдержка — заявки, тикеты, проблемы клиентов
- 🎧 ЦОК (call-центр) — обращения, ответственные
- 💰 Бухгалтерия — финансы, оплаты, счета
- 📞 Телефония — VoIP, звонки
- 🛡 ЦУС — централизованное управление сетью
Один отчёт может быть без типа (NULL) или привязан к одной категории. На странице есть фильтр-вкладки по типам.
CodeMirror + AI Builder
CodeMirror 5.65.16 — встроенный SQL-редактор в модалке:
- Подсветка синтаксиса PostgreSQL (тема material-darker, чёрный фон);
- Live-counter параметров — автоматически считает
:Имя|тип$в коде; - Подсветка плейсхолдеров жёлтым overlay'ем;
- Hot-keys: Ctrl+/ comment, Ctrl+F find, Tab indent;
- Auto-fix SQL —
_fix_sql_column_case()для миграций Carbon4 → PostgreSQL (uppercase ID → lowercase id).
AI Builder: кнопка «✨ AI» в toolbar. Открывает чат с AI-ассистентом:
- Оператор описывает что нужно: «Топ-10 должников за месяц с балансом и телефоном»;
- Ассистент задаёт уточняющие вопросы (период, фильтры);
- Возвращает готовый SQL с правильными именами таблиц/полей и параметрами;
- Оператор проверяет, при необходимости правит, сохраняет.
Контекст БД для ассистента — schema из information_schema.columns для 15 ключевых таблиц + критические правила биллинга (DB_MONEY_KOEF, MPTT-фильтры, регистр имён).
Отчёты в ЛК клиента
Если у отчёта ALLOW_IN_CABINET=true — он показывается клиенту в ЛК (раздел «Мои отчёты»). При запуске:
- Параметры
:Клиент|select[Abonents]$автоматически фиксируются текущим клиентом (нельзя посмотреть чужие данные); - Параметры дат/сумм клиент задаёт сам;
- Результат отображается с пагинацией, экспорт в CSV.
report_executions и AdminCustomReportsHistory ссылаются на отчёт с FK NO ACTION. Если есть история запусков — удаление падает с ошибкой. Сначала очистите историю или используйте архивирование (поле archive=true).
4.1. Библиотека отчётов
URL: /admin/reports/AdminCustomReports/
Каталог пользовательских SQL-отчётов. Отчёт — это сохранённый SQL-запрос с настраиваемыми параметрами, сгруппированный по типам (Техсервис, Бухгалтерия, Руководство, Поддержка и т.д.), который оператор запускает кликом и получает таблицу с возможностью экспорта в Excel, CSV или DBF.
Как найти готовый отчёт, запустить его с параметрами, выгрузить результат и завести свой — включая AI-помощника по SQL.

Список отчётов
- Вкладки по типам с цветными бейджами: 🛠 Техсервис, 📈 Руководство, ⛑ Техподдержка, 🎧 ЦОК, 💰 Бухгалтерия, 📞 Телефония, 🛡 ЦУС. Тип хранится в
AdminCustomReportsType, редактируется через кнопку «+» в правой части toolbar. - Поиск по имени и SQL-коду с шорткатом Ctrl+K.
- Звёздочка избранного — отмеченные отчёты попадают в виджет «Избранные отчёты» на дашборде директора и в профиле сотрудника.
- Бейдж «🤳 ЛК» у отчётов с
allow_in_cabinet=True— они доступны клиенту в его ЛК (например, «История платежей»). - Sticky toolbar при скролле — поиск, фильтр избранного, кнопки «+ Типы», «+ Добавить отчёт», «✨ AI» остаются видны.
- Кнопки в строке: ▶ Запустить, ✏ Редактировать, 🗑 Удалить с подтверждением через Bootstrap-confirm.
- Bulk-операции: чекбокс-колонка с master-чекбоксом, sticky-toolbar при выборе — Удалить / Сменить тип / Экспорт CSV выбранных.
- На мобильном (≤575px) — read-only режим: только имя + кнопка ▶ Запустить, CRUD скрыт.
Запуск отчёта
URL: /admin/reports/AdminCustomReports/<id>/executesql/
Кнопка ▶ Запустить в строке списка ведёт на форму с параметрами отчёта. Параметры извлекаются из SQL-кода по синтаксису :Имя|тип$ и рендерятся в форму автоматически.

На скриншоте — форма отчёта «Действия сотрудника» (#136): три параметра — Дата с, Дата по, Сотрудник. По умолчанию период — последний месяц (07.04 → 07.05), сотрудник = «Все сотрудники».
Внизу формы — четыре кнопки действий:
- Выполнить — открывает результат в HTML-таблице (на этой же странице).
- Excel (.xlsx) — скачивает результат как Excel-файл.
- CSV — скачивает CSV (UTF-8 BOM, разделитель
;для Excel RU). - DBF — экспорт в DBF (legacy формат для интеграции с 1С).
Пример: запуск с фильтром по конкретному сотруднику
Выбор конкретного сотрудника из выпадающего списка choices:

На скриншоте — выбран сотрудник uspeshnyy (Aleksandr Uspeshnyy), период 01.05.2026 → 07.05.2026. Список доступных значений для параметра :Sotrudnik|choices[...]$ формируется на лету: SQL-генератор выбирает уникальных owner из AuditOperations и подставляет их в опции.
Пример: результат выполнения
После клика «Выполнить» срабатывает редирект на /admin/reports/AdminCustomReports/<id>/history/<run_id>/ — каждое выполнение получает свой run_id (хранится 30 дней для повторного открытия результата без перезапуска SQL):

На скриншоте — результат отчёта «Действия сотрудника» за месяц: 604 строки, колонки #, Дата/время, Сотрудник, ФИО, Событие, IP-адрес, Подробности. Каждая строка — один аудит-event с детализацией («FIN_TYPES: Тип фин. операции #28 «Перевод средств…»», «ABONENTS: создан клиент…», «USERS_USLUGA: услуга подключена…»).
Возможности страницы результата:
- Sticky-заголовок таблицы при прокрутке — колонки видны всегда.
- Поиск по таблице (Ctrl+K) — клиентский фильтр без перезапуска SQL.
- Кнопки экспорта в шапке — Excel / CSV / DBF (тот же набор что на форме параметров, но без перезапуска).
- Кнопка «← Назад к форме» — возврат к форме параметров для перезапуска с другими значениями.
- История запусков — каждый запуск сохраняется в
AdminCustomReportsHistoryс user_id, params, row_count, execution_time.
Модалка редактирования отчёта
Открывается кликом по имени отчёта или по карандашу. Делится на две колонки:
- Слева: название, описание, тип (select), Bootstrap-switch «🤳 Доступен в ЛК», развёрнутая справка по 4 типам параметров (
:Имя|date$,:Имя|sum$,:Имя|select[Model]$,:Имя|choices[v1^Лейбл1|v2^Лейбл2]$) с примером SQL-сниппета. - Справа: SQL-редактор CodeMirror 5 с подсветкой синтаксиса PostgreSQL, тёмная тема
material-darker, номера строк, перенос длинных строк, soft-wrap. Hot keys: Ctrl+/ toggle comment, Ctrl+F find. Параметры:Имя|тип$подсвечиваются жёлтым фоном через CodeMirror-overlay.
Live-counter под редактором обновляется на каждом change-event: «N строк · M парам.», справа от него — список найденных параметров с типами.
Синтаксис параметров
Параметры записываются в SQL как :Имя|тип$ и автоматически становятся полями формы запуска:
| Тип | Синтаксис | UI-элемент | Передаётся в SQL как |
|---|---|---|---|
| date | :Дата с|date$ |
Календарь (jQuery datepicker) | String '2026-05-07' (ISO) |
| sum | :Сумма|sum$ |
Числовое поле (₽) | Float (умножается на 10^10 при необходимости) |
| select[Model] | :Клиент|select[Abonents]$ |
Select2 с AJAX-поиском | Integer (pk выбранной записи) |
| choices[v^L|v^L] | :Месяц|choices[1^Янв|2^Фев]$ |
Выпадающий список фикс. значений | String (значение выбранной опции) |
| choices[[code^]Label] | :Sotrudnik|choices[[uspeshnyy^]Aleksandr] |
Расширенный выпадающий с экранированными значениями | String (code) |
Пример SQL с параметрами:
SELECT a.id, a.name, a.contract_number,
aa.ostatok / 10000000000.0 AS balance_rub
FROM abonents a
LEFT JOIN admin_accounts aa ON aa.id = a.account_id
WHERE a.is_folder = false
AND a.deleted = false
AND aa.ostatok < -:Долг|sum$ * 10000000000
AND a.create_date BETWEEN :Дата с|date$ AND :Дата по|date$
ORDER BY aa.ostatok ASC
LIMIT :Лимит|sum$;
AI-помощник написания SQL
Кнопка «✨ AI» в шапке открывает чат с ИИ-ассистентом. Ассистент знает структуру 15 ключевых таблиц биллинга (abonents, admin_accounts, tarif, finance_operations, users_usluga, pay_log, users, homes, nas, connection_points и др.) и формат параметров, умеет писать SQL по словесному описанию задачи.
Типичный сценарий:
- Оператор пишет: «топ-10 должников за месяц с балансом и телефоном»
- AI задаёт уточняющие вопросы: какой период (последний месяц / произвольный), какой минимальный долг, нужен ли фильтр по тарифу
- Оператор отвечает свободным текстом
- AI возвращает готовый SQL с блоком JSON
{"name": "...", "description": "...", "sql": "..."} - Зелёный draft-banner с кнопкой «➡ Создать отчёт» передаёт черновик в основную модалку с предзаполненными name/description/sql
- Оператор проверяет SQL в CodeMirror, при необходимости правит, нажимает «Сохранить»
Каждый AI-запрос пишется в AuditOperations (table_name='ADMIN_CUSTOM_REPORTS', descr='AI-консультация: …'). Запросы идут через прокси (внешний API провайдера недоступен для RU).
Права и audit
- SQL выполняется с правами Django БД-юзера (с полным доступом к БД). Это значит, что любой оператор с правом «Запуск отчётов» может прочитать любую таблицу. Опасные SQL (UPDATE, DELETE, DROP) не блокируются на уровне приложения — защита только через PostgreSQL-роль (рекомендуется отдельный read-only role для отчётов).
- Каждое выполнение пишется в AdminCustomReportsHistory: user_id, params (JSON), row_count, execution_time, sql_hash. Доступно через «История запусков» в правом меню отчёта.
- allow_in_cabinet=True: отчёт доступен клиенту в ЛК через
/lk/reports/<id>/. Для безопасности параметры могут содержать только типdateиsum(запрещеныselect[Model]иchoices, иначе клиент мог бы перебирать ID).
Переработка раздела
Раздел переработан: нерабочие отчёты вычищены, редактор запросов приведён к тому же виду, что в СОРМ, у отчётов появились обложки и разделение по организациям.
- Библиотека отчётов
- Список
- Вкладки по отделам
- Колонка Орг при мульти-орг
- Обложки-миниатюры
- Чипы и поиск Ctrl+K
- Модалка отчёта
- Редактор на всю высоту
- Кнопки AI и Формат
- Справка в popover
- Квадратная обложка
- Чекбоксы организаций
- Запуск
- Единый выбор периода
- Выбор сотрудника с аватаром
- История выполнения
- Безопасность
- Параметры связанные
- Нормализация дат
- Привязка к организации
Три критические находки
| Было | Стало |
|---|---|
| Редактор открывался пустым (чёрный прямоугольник) | Пересчёт размеров после показа окна — SQL виден сразу |
| Значение параметра вставлялось в запрос текстом (риск подмены, апостроф ломал фильтр молча) | Значения передаются связанными параметрами; даты нормализуются — подмена невозможна |
| Поля периода шли «Дата конца → Дата начала» (по алфавиту) | Порядок по появлению в запросе — начало перед концом |
Как выполняется отчёт с параметрами
flowchart LR
FORM["Форма запуска"] --> P["Параметры формы"]
P --> SUB["Подстановка плейсхолдеров %s"]
SUB --> NORM["Нормализация дат
дд.мм.гггг в дату"]
NORM --> EXEC["Выполнение со связанными
значениями"]
EXEC --> HIST["Запись в историю"]
EXEC --> RES["Результат или ошибка"]
Значение больше не встраивается в текст запроса, поэтому апостроф или «;» внутри него не могут изменить смысл SQL. База работает в режиме, где строку «23.06.2026» она читала как «месяц 23» и падала — теперь дата передаётся отдельным типом и понимается однозначно.
Чистка: 75 → 62 отчёта
| Действие | Отчётов | Причина |
|---|---|---|
| Удалено | 18 | Отчёты на пустых устаревших таблицах (старая телефония, старый лог RADIUS) и дубли |
| Починено | 3 | Выручка по организациям (был пустой запрос), расходы за период |
| Добавлено | 5 | Сводка по организациям, выручка по дням и по месяцам, обещанные платежи, отток |
Редактор как в СОРМ + обложка
- Поле кода на всю высоту окна, компактный шрифт, кнопки AI (помощник по SQL) и Формат (автоформатирование) над редактором.
- Справка по параметрам вынесена из левой колонки в ссылку-подсказку «Параметры в SQL» под редактором.
- Квадратная обложка: любую картинку модуль обрезает по центру до 512×512 и кладёт в облачное хранилище; в списке она показывается миниатюрой.
Разделение по организациям
flowchart TB
R["Отчёт"] --> Q{"Привязан к организациям?"}
Q -- "Нет" --> ALL["Общий — виден всем"]
Q -- "Да" --> ORG["Виден отмеченным организациям"]
ORG --> COL["Колонка «Орг.» в списке
в режиме «Все организации»"]
ORG --> CHK["Чекбоксы в шапке модалки"]
Организации отмечаются чекбоксами по центру шапки модалки; пустой список означает «общий отчёт». В режиме «Все организации» в списке между «№» и названием появляется колонка «Орг.» с бейджами — как в тарифах.
Единые компоненты
| Где | Что было | Стало |
|---|---|---|
| Форма запуска — даты | Два отдельных поля с календарём | Единый выбор периода с пресетами (работает в любом отчёте с парой дат) |
| Форма запуска — сотрудник | Обычный выпадающий список | Селектор сотрудника с аватаром |
| Редактор кода | Свой код в каждом разделе | Единый компонент (каталог компонентов интерфейса) |
Тёмная тема и телефон
Тёмная тема выдержана целиком; на телефоне список сжимается до имени и кнопки запуска, а модалки раскрываются на весь экран выдвижной панелью.
4.2. Аудит
Журнал всех значимых действий в биллинге: создание, изменение, удаление клиентов, подключение услуг, платежи, блокировки, изменения настроек, действия СОРМ.

Каждая запись содержит дату/время, оператора, тип события, клиента и описание. Для большинства событий есть drill-down: клик по записи открывает изменённый объект в нужной вкладке.
Возможности списка:
- Фильтр периода с кнопками Сегодня / Неделя / Месяц / Год.
- Фильтр по типу события и текстовый поиск.
- Цветные бейджи категорий (status / block / payment / SORM).
- Sticky-заголовок таблицы при прокрутке.
4.3. Журнал платежей
Сводный журнал финансовых операций по всем клиентам — приходы, списания, сторно, обещанные платежи. Это представление таблицы FinanceOperations с серверной пагинацией (поддерживает сотни тысяч записей).

Возможности:
- Быстрые периоды: Сегодня / Неделя / Месяц / Квартал / Год.
- Селектор количества строк: 50 / 100 / 200 / 500.
- Цветовое кодирование сумм: приход — зелёный, расход — красный.
- Клик по клиенту открывает его карточку в новой вкладке.
- Серверный фильтр по типу операции и текстовый поиск.
- По умолчанию показан текущий месяц.
Переработка журналов
У обоих журналов общий набор инструментов: выбор периода, показатели, цветные категории, поиск и экспорт. К ним добавлены разделение по организациям, работа с телефона и единый визуальный язык.
- Журналы: Аудит и Платежи
- Единый вид SmitUI
- Чистая таблица без серой шапки
- Бейджи-таблетки с точкой
- Тёмная тема из общего источника
- Токены отступов и границ
- Разделение по организациям
- Колонка Орг в режиме Все
- Фильтр по доступным компаниям
- Записи без организации видны всем
- Работа с клиентом
- Клик открывает боковую панель
- Панель всегда поверх меню
- Телефон
- Строки становятся карточками
- Подписи полей у значений
- Полоса прихода или расхода слева
Разделение по организациям
Теперь данные разделены. У платежа организация берётся из самой операции; у аудит-записи — из связанного объекта.
flowchart TB
A["Аудит-запись"] --> Q{"Есть клиент?"}
Q -- "Да" --> AB["Организация клиента"]
Q -- "Нет" --> OBJ{"Известен объект?"}
OBJ -- "Платёж / видеопроект /
тикет / NAS" --> OO["Организация объекта"]
OBJ -- "Нет" --> ALL["Без организации —
общесистемное, видно всем"]
AB --> COL["Колонка «Орг.» + фильтр
по доступным компаниям"]
OO --> COL
| Раздел | Как определяется организация | Покрытие |
|---|---|---|
| Журнал платежей | Поле организации у самой финоперации | Практически все записи |
| Аудит | Организация клиента; для системных — по объекту (платёж, видеопроект, тикет, NAS) | ≈ 74% записей; остальное — общесистемные события «—», видны всем |
Единый вид SmitUI и работа с клиентом
- Обе таблицы выглядят одинаково: чистая шапка без заливки, воздушные строки, бейджи-таблетки с точкой-индикатором, тёмная тема без отдельных настроек.
- В Журнале платежей знак операции показывает тонкая цветная полоса слева и цвет суммы (вместо заливки всей строки); суммы выровнены по правому краю.
- Клик по клиенту открывает боковую панель с его данными (баланс, контакты, последняя сессия) прямо поверх журнала — не уводя со страницы. Панель всегда поверх бокового меню.
Телефон
На телефоне строки обоих журналов становятся карточками: у каждого значения — подпись поля, ничего не обрезается. В Журнале платежей слева остаётся цветная полоса прихода/расхода.
4.3.1. Очередь чеков (54-ФЗ)
Раздел Отчёты → Очередь чеков (/admin/reports/fiscal_queue/)
показывает, какие операции ждут кассового чека, по каким чек уже пробит и где ОФД вернул
ошибку. Отсюда же чек отправляется вручную — по одной операции или пачкой.
Модуль фискализации, настройка «какие платежи фискализируем» и чек-лист готовности описаны в разделе 6.3.1. Модуль фискализации 54-ФЗ; сама очередь — там же.
4.4. Журнал сообщений
Единый сводный журнал всех сообщений (MsgStack) по всем клиентам — SMS,
Email, Telegram, Push, VK, ЛК. И точечные отправки из карточки клиента, и массовые
рассылки попадают в один список. Доступен по адресу /admin/reports/messages/
(пункт меню «Отчёты → Журнал сообщений»,, единый вид SmitUI и
мульти-орг).

Карта раздела
- Журнал сообщений
- Показатели
- Всего за период
- Доставлено SMS
- В очереди
- Ошибки SMS
- Фильтры
- Поиск текст договор
- Диапазон дат
- Чипы каналов
- SMS-статус
- Отправитель
- Организация
- Таблица SmitUI
- Колонка Орг
- Бейджи каналов
- Полоса ошибок SMS
- Карточки на телефоне
- Рассылка
- Категории
- Тарифы
- Папки MPTT
- NAS
- Поиск
- Скоуп по орг
- Мульти-орг
- Фильтр по клиенту
- Записи без орг видны всем
- Рассылка своим клиентам
Что внутри
- 4 KPI-карточки сверху: Всего, Доставлено SMS (с процентом доставляемости), В очереди, Ошибки SMS. Период переключается кнопками Сегодня / Неделя / Месяц / Все.
- Фильтры: текстовый поиск по сообщению/заголовку/клиенту/договору, диапазон дат, кнопки быстрых периодов.
- Чипы каналов: Все каналы / SMS / Email / Telegram / Push / VK / Только ЛК.
- Фильтр SMS-статуса справа: только delivered / sent / pending / failed.
- Колонка «Отправитель» показывает кто отправил каждое
сообщение.
Aleksandr Uspeshnyyдля ручных отправок, Система — для автоматических (биллинг, Celery, webhook). Рядом — фильтр Отправитель — любой / Мои / Системные + список всех операторов с рассылками. - Цветные бейджи каналов с tooltip'ами: ✓✓ delivered, ✓ sent, ⏱ pending, ✕ failed (для SMS — на основе webhook-статуса sms-gate.app).
- Клик по строке открывает модалку с полным текстом и деталями (на телефоне — полноэкранная слайд-панель, выезжает справа).
- Колонка «Орг.» — при включённых мульти-организациях и режиме «Все организации» показывает организацию клиента цветным бейджом OrgBadge. Записи без клиента (системные) — «—».
- Pagination 25/50/100/200, server-side.
- Экспорт CSV текущей выборки (UTF-8 BOM, разделитель
;, лимит 50 000 строк; в режиме «Все организации» — с колонкой «Орг.»).
Разделение по организациям
Раздел учитывает мульти-организации. Сообщение
связано с клиентом (MsgStack.abonent), у клиента есть организация — журнал
фильтруется по ней, а рассылка не может уйти клиентам чужой компании.
flowchart TD
REQ["Запрос журнала
или рассылки"] --> MO{"Мульти-орг
включён?"}
MO -->|"нет"| ALL["Без фильтра —
все записи"]
MO -->|"да"| CUR{"Выбрана орг
в шапке?"}
CUR -->|"да"| ONE["Только клиенты
этой организации"]
CUR -->|"нет"| ISO{"Изоляция
персонала?"}
ISO -->|"выключена"| ALLORG["Все организации
+ колонка «Орг.»"]
ISO -->|"включена"| PERM["Только доступные
оператору орг"]
ONE --> NULL["+ записи без клиента
видны всем (NULL)"]
ALLORG --> NULL
PERM --> NULL
Журнал, KPI и CSV заскоуплены через _apply_msg_org() по
abonent__organization_id. Контракт: записи без определимой организации
(системные, без клиента) видны всем — иначе «ничьи» уведомления пропали бы у всех.
Рассылка — критично (P0). Набор получателей строится из единого
base-queryset, который заранее ограничен доступными организациями
оператора. Поэтому все режимы выбора (категории / тарифы / папки / NAS /
поиск / выбор по ID) не могут захватить клиентов чужой компании — ни в предпросмотре,
ни при отправке.
Массовая рассылка
Кнопка «Рассылка» в правом верхнем углу открывает модальное окно для отправки одинакового текста группе клиентов через выбранные каналы (SMS / Email / Telegram / Push). Hard-limit — 500 получателей на одну рассылку (защита от случайного спама).
5 способов выбора получателей:
- Категории — 8 готовых chip-фильтров: Должники, Сейчас онлайн, Заблокированные, Об. платёж, Юр. лица, Без email, Без телефона, Не платил 30 дн.
- Тарифы — multi-select из ~78 тарифов. Отправит всем клиентам на выбранных тарифах.
- Папки — древовидный picker с MPTT-обходом всех вложенных подпапок автоматически. Поиск по имени, expand/collapse, кнопка очистки выбора.
- NAS — multi-select NAS-серверов. Отправит всем клиентам с
учётками на выбранных NAS (через
Users.nas_id). - Поиск — Select2 AJAX по имени/договору для точечного выбора.

Live-preview снизу всегда показывает: фактическое количество получателей, первые 10 имён + «…и ещё N», статистику доступности каналов («SMS: 267 · Email: 13 · TG: 0 · Push: 1»). Кнопка «Отправить» дизаблится при count = 0 или count > 500 (бейдж становится красным «макс 500!»).
Счётчик символов и SMS-сегментов справа от лейбла «Текст» обновляется на каждый ввод. Кириллица (UCS-2) → 70 символов на сегмент, латиница (GSM 7-bit) → 160. Цвет меняется на оранжевый при ≥2 сегментов и красный при ≥3.
Дерево папок
Вкладка «Папки» отрисована как полноценное tree-list с иконками и счётчиками клиентов в каждой папке (включая подпапки). Поддерживается keyboard-навигация (Tab → Enter/Space), live-фильтр по имени с автоматическим раскрытием родителей, кнопки Раскрыть всё / Свернуть всё / Очистить выбор.

Рассылка по NAS-серверам
Полезно когда нужно предупредить клиентов конкретного NAS (профилактические работы, замена оборудования, миграция). Каждый NAS показывается с IP, статусом (включён / выкл) и количеством клиентов.

Аудит рассылок
Каждая отправка пишется в AuditOperations (категория «Сообщения», см. раздел 4.2 Аудит):
- Точечная отправка (карточка клиента → «Отправить»):
«Сообщение #N → Иванов И.И. (SMS, Email): «текст…»»с указаниемowner= текущий оператор. - Массовая рассылка — одна summary-запись на всю операцию:
«Рассылка: uspeshnyy → категория «business» (SMS, EMAIL), получателей: 270/270: «текст…»».
Поле MsgStack.owner_id хранит pk оператора, поэтому в журнале можно
отфильтровать «все мои отправки» или «всё что отправлял Петров».
Модалка деталей
Клик по строке открывает полный текст сообщения, дату, клиента и статусы всех каналов доставки. Из неё — переход в карточку клиента.

Адаптивность и единый вид SmitUI
Раздел приведён к единому виду SmitUI: чистая шапка таблицы без серого фона и sticky, бейджи-таблетки, единый источник тёмной темы. Красная полоса у строк с ошибкой SMS сохранена.
- Таблица → карточки на телефоне (≤767px): вместо скрытия колонок
каждая строка превращается в карточку с подписями полей (
data-label) — видна вся информация, а не урезанная. KPI перестраивается в 2×2 grid. - Модалки → полноэкранные слайд-панели: на телефоне
и детальная модалка, и модалка рассылки разворачиваются на весь экран (100dvh) и
выезжают справа; шапка и футер прилипают (заголовок и кнопки действий всегда видны),
тело скроллится.
prefers-reduced-motionотключает анимацию слайда.
Endpoint'ы
| URL | Назначение |
|---|---|
GET /admin/reports/messages/ | Главная страница |
GET /admin/reports/messages_json/ | Server-side список (фильтры + pagination) |
GET /admin/reports/messages_kpi/ | JSON для KPI-карточек |
GET /admin/reports/messages/export/ | CSV экспорт текущей выборки |
POST /admin/reports/messages/broadcast/ | Массовая отправка |
GET /admin/reports/messages/recipients_preview/ | Preview получателей перед рассылкой |
GET /admin/reports/messages/tariffs_list/ | Список тарифов (для multi-select) |
GET /admin/reports/messages/folders_list/ | Дерево папок (для tree-picker) |
GET /admin/reports/messages/nas_list/ | Список NAS-серверов |
GET /admin/reports/messages/senders_list/ | Список операторов с рассылками (для select-фильтра) |
4.5. Разработка и логи
Раздел для администратора-разработчика. Доступен только пользователям с правами root. Делится на две вкладки.
Отчёты — встроенный markdown-просмотрщик внутренних документов проекта (отчёты по разработке, планы, документация).

Поддерживается сортировка по дате/имени или ручной drag-and-drop, inline-переименование, создание папок, загрузка новых .md-файлов через интерфейс.
Возможности просмотрщика .md
Markdown-просмотрщик поддерживает удобную навигацию и работу с документами:
- Поиск по документам — поле над списком файлов. Ввод фильтрует
список по имени мгновенно; нажатие Enter запускает полнотекстовый поиск
по содержимому всех документов — с подсветкой числа совпадений и сниппетом. Горячая
клавиша
Ctrl+Fставит фокус в поиск. - Кликабельные ссылки на разделы биллинга — пути вида
/admin/...,/lk/...и полныеhttp(s)прямо в тексте документа становятся ссылками (с иконкой) и открываются в новой вкладке. - Переходы между документами — ссылки на другие .md-файлы (отчёт → план → ТЗ) открываются в том же просмотрщике, превращая документы в связанную базу знаний.
- Чек-листы — пункты
- [ ]/- [x]отображаются как ☐ / ☑ (выполненные зачёркнуты). - Вложенные списки — многоуровневые перечни сохраняют отступы.
- Копирование кода — кнопка «копировать» при наведении на блок кода (команды деплоя, SQL).
- Диаграммы Mermaid и комментарии к заголовкам (командное обсуждение прямо в документе).
Логи — просмотр серверных логов прямо из админки.

Доступны каналы:
error.log— общие ошибки приложения;payment.log— платежи (ЮKassa, W1, webhook);radius.log— авторизация и accounting;sorm.log— выгрузка СОРМ;staff.log— действия сотрудников;celery_worker.log,celery_beat.log— фоновые задачи;nginx_access.log,nginx_error.log— веб-сервер;freeradius.log— нативные логи FreeRADIUS.
Показываются последние 500 строк, есть кнопка обновления. Файлы автоматически ротируются (10 МБ × 5 копий).
4.6. Должники
Содержание раздела
Отдельная страница /admin/debtors/ — список клиентов с отрицательным балансом
или активной блокировкой b_negbal. Раздел рассчитан на ежедневную работу
бухгалтерии и операторов поддержки: KPI-блок сверху помогает быстро оценить
ситуацию по компании, а drawer-панель — разобраться с конкретным клиентом без
ухода на полную карточку.
KPI и статистика по периодам
Над таблицей — четыре карточки-показателя: общее количество должников, суммарный долг (в рублях), средний долг и доля должников с активным обещанным платежом. Карточки реагируют на выбранный период: переключатель chips сверху позволяет видеть динамику за сегодня / неделю / месяц / квартал / год. Цифры пересчитываются прямо в браузере без перезагрузки — у каждой карточки есть мини-индикатор изменения относительно предыдущего периода.
Фильтры и чипы
- Период — chip-фильтр (сегодня, неделя, месяц, квартал, год, всё время). Активный чип подсвечивается.
- Категория — отдельные чипы: с обещанным платежом, с контактом и небольшим долгом (кому имеет смысл звонить), заблокированные, без оплат за 60 дней.
- Поиск — по ФИО, договору, телефону, email — мгновенный фильтр без перезагрузки.
- Состояние сохраняется — выбранный период и чип запоминаются в URL, ссылку можно отправить коллеге.
Таблица и сортировка
Колонки: ФИО, договор, тариф, точка подключения, баланс, дней без оплаты, телефон, email, статус. По умолчанию сортировка — по убыванию суммы долга. Клик на заголовок любой колонки переключает порядок (▲▼). Цветовое кодирование: красные строки — заблокированные за неуплату, жёлтые — на грани блокировки, серые — с активным обещанным платежом. В каждой строке справа — кнопка ℹ Подробнее, которая открывает drawer.
Drawer-панель клиента
Клик на ℹ открывает боковую панель справа (overlay поверх таблицы) с краткой сводкой по клиенту — без перехода на полную карточку и потери контекста списка. Внутри панели:
- Шапка: ФИО, договор, тариф, тек. баланс, дата последней оплаты, статус блокировки.
- График: динамика баланса за последние 3 месяца — наглядно видно, когда «ушёл в минус».
- Последние финансовые операции (топ-10): дата, тип (приход/расход), сумма, описание.
- Сообщения: история отправленных SMS/Email/Push с галочками доставки.
- Комментарии операторов: можно добавить новый комментарий прямо из drawer (хранится в
AbonentsComments), история подписана автором и временем. - Лицевые счета: связанные счета с остатками (если у клиента несколько).
- Действия: отправить SMS-напоминание о долге, активировать обещанный платёж, открыть полную карточку.
Массовые действия и экспорт
- Чекбоксы в каждой строке + выбрать все на странице — для bulk-операций над отмеченными должниками.
- Действия над выбранными: массовая отправка SMS/Email, блокировка, прощение долга (создаёт компенсирующий FinOp).
- Экспорт CSV (UTF-8 BOM, разделитель
;) — выгружает текущую выборку с учётом фильтров для сверки с бухгалтерией или загрузки в 1С.
4.7. Миграция с других биллингов
Раздел /admin/settings/migration/ — мастер импорта данных клиентов из других
биллинговых систем. Пошаговый wizard с предпросмотром и dry-run.
Импорт из предыдущей версии (Firebird)
/admin/settings/migration/cb4/ — специализированный импорт данных
из предыдущей версии биллинга (Firebird). Учитывает специфику:
- Денежные поля × 10⁷ → нормализуются в × 10¹⁰ (новый
DB_MONEY_KOEF). - PGP-зашифрованные пароли NAS → расшифровываются через ключ из EBS audit log.
- MPTT-дерево клиентов с папками сохраняется через
parent_id. - Услуги маппятся через таблицу соответствий (legacy
USLUGA.ID→ новый pk). - RADIUS-сессии и
USERS_RADIUSAUTHмигрируются последним этапом.
Загрузка из CSV
/admin/settings/migration/csv_loading/ — общий импорт клиентов/услуг/платежей
через CSV файлы. Поддерживается:
- Загрузка через UI (drag-and-drop) или путь к файлу на сервере.
- Маппинг колонок CSV ↔ поля модели через интерактивную форму.
- Dry-run перед применением — показывает что будет создано/обновлено/пропущено.
- Отчёт по результатам с подсветкой ошибок построчно.
Авто-импорт CSV (схемы)
/admin/settings/autocsv/ — настройка повторяющихся импортов:
оператор сохраняет «схему» (маппинг колонок + способ обработки дубликатов), и потом
загрузка одной кнопкой берёт CSV и применяет схему без повторной настройки. Полезно для
ежемесячных выгрузок из бухгалтерии или экспорта из биллинга мобильного оператора (массовое
зачисление платежей).
FrameworkFormGroupFields — назначение и роль
Содержание раздела
FrameworkFormGroupFields (FFG) — таблица настроек UI для всех админских форм биллинга. Управляет тем, какие поля видны на форме редактирования, как они сгруппированы в вкладки и в каком порядке. По сути это «генеральный настройщик» админки без правки кода.
Что это и зачем
Биллинг — это унаследованный движок с десятками моделей, у каждой по 30-100 полей. Большая часть из них — технический шум для оператора. Решения:
- Без FFG — generic-форма со всеми 100 полями. Оператор не знает что важно;
- С FFG — оператор видит только нужные 10 полей, разбитые по 3 вкладкам с понятными русскими названиями. Скрытые поля остаются в БД и работают.
Это безопасный способ упростить UI без боязни сломать логику.
Ключевые поля
| Поле | Назначение |
|---|---|
TABLE_NAME | Имя модели (USERS, ABONENTS, USLUGA — UPPERCASE) |
FIELD_NAME | Имя поля Django-модели (то же что в Model._meta.fields) |
INTERFACE_ID | FK на интерфейс (NULL = дефолт для всех ролей) |
GROUP_ID | Номер вкладки/группы в форме (1 = основные, 2 = доп., и т.д.) |
SHOW_ON_FORM | 0 = скрыто, 1 = видно (главное поле управления) |
VERBOSE_NAME | Русское имя поля для UI (заменяет автоматическое из модели) |
ORDER | Порядок в группе (для drag-and-drop) |
Как работает
- При открытии формы редактирования модели (например
/admin/Abonents/<id>/) view вызываетsafe_globals.get_groups_from_model('ABONENTS'); - Функция читает все записи FFG где
TABLE_NAME='ABONENTS'иINTERFACE_ID IS NULL; - Записи группируются по
GROUP_ID→ каждая группа = одна вкладка формы; - Внутри группы поля сортируются по
ORDER, скрытые (SHOW_ON_FORM=0) исключаются; - Применяются
VERBOSE_NAMEдля русификации лейблов; - Кеш Django сохраняет результат — после изменения FFG нужен
cache.clear().
Опасные моменты
INTERFACE_ID=NULL— это дефолт, не «отсутствие настройки». Если полеSHOW_ON_FORM=0дляINTERFACE_ID=NULL, оно скрыто во всех интерфейсах. Чтобы показать только в одном — нужны 2 записи:NULLс 0 иINTERFACE_ID=1с 1;- Дубликаты Python dict — баг был с
'Users'ключом, появлявшимся дважды в_EXCLUDE_FORMS. Второе значение тихо перезаписывало первое. Перед добавлением нового ключа всегдаgrep; - UPPERCASE имя таблицы — критично для PostgreSQL.
'abonents' != 'ABONENTS'. ИспользуйтеModel._meta.db_table.upper()чтобы не ошибиться; - FIELD_NAME — Django-имя, не SQL-имя. Поле
create_dateв FFG, не"CREATE_DATE".
Реальные примеры скрытия полей
| Build | Модель | Скрыто |
|---|---|---|
| Users (учётные записи) | 17 полей: IPV6, MASK, PHONE, EXT_ID, NAS_IP_LOCK, OPT82, IS_TEMPLATE, SNAT_PULL, SNATIP, SERVER, ALWAYS_LOGGED, HOST_IP, HOST_PULL, CREATE_DATE, OPT82_PARAM, IS_ALLOW_SEARCH, GPON_MODEM_PORT, HW_SERIAL, EQUIPMENT, SERVICE_TYPE | |
| Usluga | SERVICE_TYPE (87% услуг имели его NULL) | |
| Users группа 32 | 5 «дополнительных»: DHCP_MASK, DHCP_ROUTE_IP, ASK_PASSWORD_LK, DEACTIVATE_STRING, ACTIVATE_STRING |
/admin/settings/interface_settings/ (FrameworkFormGroupFieldsForm в billing/forms/framework_forms.py). После сохранения обязательно очистите кеш — иначе изменения не подхватятся: docker exec app-web-1 python manage.py shell -c "from django.core.cache import cache; cache.clear()"
4.8. Настройки интерфейса (формы)
/admin/settings/interface_settings/ — конфигурация полей форм для каждой
модели. Через FrameworkFormGroupFields можно:
- Скрывать/показывать поля без правки кода (флаг
show_on_form). - Менять порядок полей (drag-and-drop).
- Группировать поля по вкладкам (
FrameworkFormGroup). - Делать поля required / readonly через UI.
Пример использования: на форме Users скрыты 17 технических полей (IPV6, MASK,
EXT_ID, IS_TEMPLATE, и т.д.) — оставлены только реально используемые. Изменения применяются
для всех операторов одновременно после cache.clear().
5. Игры (Маркетинг)
Модуль «Игры» — часть раздела «Маркетинг» — геймификация для удержания и вовлечения клиентов: 8 встроенных аркад, турнирная таблица и розыгрыш «Игра месяца» с бесплатным месяцем интернета победителю.
Список игр: Pacman, Tetris, Snake, Minesweeper, 2048, Breakout, Flappy Bird, Helicopter. Доступны в админке, мобильном приложении и ЛК.
5.1. Архитектура модуля
Единый источник настроек (GAMES_* в SystemSettings)
питает три точки потребления: профиль-меню админки, карточку клиента,
мобильное приложение. Данные результатов хранятся в GameScore,
история победителей — в GameMonthWinner.

| Компонент | Назначение |
|---|---|
billing/services/games_registry.py | Единый реестр 8 игр (admin + mobile) |
billing/models/game_score.py | GameScore (результаты) + GameMonthWinner (победители) |
billing/services/game_rewards.py | Определение лидера + безопасное начисление бонуса |
billing/tasks/game_rewards.py | Celery-подведение итогов 1-го числа |
settings/_marketing_tab.html | UI настроек (вкладка «Маркетинг») |
abonents_form/marketing_games.html | Вкладка результатов в карточке клиента |
5.2. Настройки модуля «Маркетинг»
Настройки находятся в /admin/settings/system/ → вкладка
«Маркетинг» (рядом с Брендинг / Безопасность / … / Профиль).
Сейчас Маркетинг = Игры; в будущем туда добавятся другие маркетинговые механики
(акции, реферальные программы, бонусы за активность).

Страница содержит 5 секций:
- Общее — Включить игры (глобальный выключатель) + Пункт «Игры» в меню профиля.
- Мобильное приложение — Разрешить игры клиентам + чекбоксы 8 доступных игр.
- Игра месяца — розыгрыш, игра, дни бесплатного интернета, минимальный счёт, режим начисления (авто/ручной).
- Условия участия — оценки в сторах / на картах (см. §5.4).
- Текущий лидер и история — live-превью лидера + список победителей.



5.3. «Игра месяца» — бесплатный интернет
Главная механика. Клиент с максимальным счётом за календарный месяц получает бесплатный месяц интернета — кредит-финоперацию на сумму месячной стоимости его тарифа.

Настройки розыгрыша:
- Игра розыгрыша — какая из 8 игр участвует в текущем месяце.
- Дней бесплатного интернета — 30 по умолчанию.
- Мин. счёт для участия — отсекает «нулевые» результаты.
- Авто-начисление / ручное — по умолчанию оператор подтверждает победителя кнопкой (защита от ошибок).
- Исключать сотрудников — результаты из админки в розыгрыше не участвуют.
- Уведомлять победителя — MsgStack + Push.
Подведение итогов — Celery-задача game_of_month_finalize
запускается 1-го числа в 02:00, определяет лидера прошлого месяца и
(в авто-режиме) начисляет приз; в ручном — ставит «ожидает подтверждения»
+ Telegram-алерт оператору.
Ручное начисление. В блоке «Текущий лидер» кнопка «Начислить победителю вручную» открывает окно подтверждения с данными победителя — игра, ФИО, договор, набранные очки и сумма приза. Если для турнира заданы условия участия (см. §5.4), оператор отмечает их выполнение прямо в окне; кнопка «Начислить» становится доступной только после подтверждения всех условий.

FinanceOperations (как онлайн-платёж), не правит баланс напрямую —
EBS-синхронизация его не затирает. Сотрудники в розыгрыше не участвуют.
Заблокированный/удалённый победитель пропускается + алерт оператору.
При равном максимуме побеждает достигший раньше (tie-break).
5.4. Условия участия в турнире
Для участия в турнире можно требовать действия, повышающие рейтинг компании:
| Условие | Настройка |
|---|---|
| ⭐ Оценка приложения (Google Play / App Store) | GAMES_OF_MONTH_REQUIRE_APP_RATING |
| 🗺 Оценка на Яндекс Картах | GAMES_OF_MONTH_REQUIRE_YANDEX_MAPS |
| 📍 Оценка на 2ГИС | GAMES_OF_MONTH_REQUIRE_2GIS |

Включённые условия показываются клиенту в мобильном приложении как требования перед участием в розыгрыше. По умолчанию все выключены.
Ссылки на оценку
Под переключателями условий задаются ссылки, по которым клиент оставляет оценку. Источники ссылок разделены:
- Ссылка на приложение — берётся из раздела
ЛК → Мобильное (
Google PlayиApp Store), чтобы не дублировать. В настройках Маркетинга она показана только для справки; если ссылки в ЛК не заполнены — выводится подсказка с переходом в нужный раздел. - Яндекс Карты и 2ГИС — задаются прямо
в настройках Маркетинга (
GAMES_OF_MONTH_YANDEX_URL,GAMES_OF_MONTH_2GIS_URL).
/mobile-api/v1/game/config и показывает их клиенту. Факт того, что
клиент действительно оставил оценку, подтверждает оператор вручную в окне
начисления приза — автоматической проверки отзыва на стороне магазинов и карт нет.
5.5. Вкладка «Маркетинг» в карточке клиента
В карточке клиента появляется вкладка «Маркетинг» — только если модуль игр включён и у клиента есть лицевой счёт.

Содержимое вкладки:
- Карточка «Игра месяца» — результат клиента vs лидер, прогресс-бар, бейдж «Лидер!» если он первый.
- Лучшие результаты по играм — по каждой игре, в которую играл клиент: лучший счёт + глобальный ранг (🏆 за 1 место, 🥈🥉 за 2–3).
- Empty-state — если клиент ещё не играл.
Оператор видит игровую активность клиента прямо в его профиле, не переходя в раздел игр.
5.6. Профиль-меню и мобильное приложение
Профиль-меню (справа у аватара) — пункт «Игры»
появляется, когда включены GAMES_ENABLED + GAMES_ADMIN_ENABLED.
Управляется через context-processor — без жёсткой проверки прав, видимость
определяется единым тогглом.

Мобильное приложение (/mobile-api/v1/game/config)
отдаёт список доступных игр (из GAMES_MOBILE_ALLOWED) и данные
текущего розыгрыша (мой счёт, счёт лидера, дни приза). Фильтрация
submit_score / leaderboard по GAMES_MOBILE_ENABLED.
Ключи настроек (SystemSettings, категория games)
GAMES_ENABLED / GAMES_ADMIN_ENABLED / GAMES_MOBILE_ENABLED / GAMES_MOBILE_ALLOWED
GAMES_OF_MONTH_ENABLED / GAMES_OF_MONTH_KEY / GAMES_OF_MONTH_REWARD_DAYS
GAMES_OF_MONTH_MIN_SCORE / GAMES_OF_MONTH_AUTO_AWARD / GAMES_OF_MONTH_EXCLUDE_STAFF
GAMES_OF_MONTH_NOTIFY / GAMES_OF_MONTH_OPTYPE
GAMES_OF_MONTH_REQUIRE_APP_RATING / _YANDEX_MAPS / _2GIS
GAMES_OF_MONTH_YANDEX_URL / GAMES_OF_MONTH_2GIS_URL
Ссылка на приложение для условий участия берётся из
MOBILE_FORCE_UPDATE_URL_ANDROID / _IOS (раздел ЛК → Мобильное).