Настройки: система и платежи
Общие настройки, печатные формы, фискализация, платёжные системы, банковские выписки и почтовый сервер.
Содержание раздела
- 6. Настройки
- 6.2. Шаблоны печати
- 6.3. Фискализация (54-ФЗ)
- 6.4. Платёжные системы
- — Общие настройки и кассы организаций
- — Секретные ключи
- — Проверка подключения
- — Безопасность webhook
- 6.4.1. Банковские выписки (автообработка)
- 6.4.2. Банки и парсеры
- 6.4.3. Очередь модерации
- 6.4.4. Журнал импортов
- — UX-полировка и единые компоненты
- 6.4.5. Почтовый сервер (SmitMailServ)
- 6.4.5А. Домены и DNS (Cloudflare)
- 6.4.6. Автонастройка почтовых ящиков и DNS
6. Настройки
Раздел меню «Настройки» объединяет все параметры биллинга, интеграции, шаблоны печати, управление персоналом и обслуживание базы данных.
6.1. Настройки системы
Единая страница системных параметров с тремя вкладками: Параметры, Брендинг, Безопасность.
Вкладка «Параметры» — общие настройки биллинга, сгруппированные по типам: RADIUS, валюта, ЛК, общие, сообщения, учёт, интерфейс. Каждая настройка имеет имя, значение и описание.

Примеры параметров: лимит обещанного платежа в днях, частота auto-assign NAS, SLA-цели для NAS-мониторинга, частота автоматической очистки БД.
Вкладка «Брендинг» — фирменное оформление: название компании, логотип, цвет акцента, контактные данные. Эти данные показываются в админке, в личном кабинете и в шаблонах печати.

Вкладка «Безопасность» — политика финансовых операций
На Безопасности — глобальные ограничения для ручных
финансовых операций (создание/редактирование/удаление через UI). Доступна
только пользователям группы root или is_superuser=True.
5 настроек (все по умолчанию выключены — стандартное поведение Django admin):
| Toggle | Что меняет |
|---|---|
| Только суперпользователь может проводить ручные операции | Скрывает кнопки «Приход»/«Расход», иконки редактирования и удаления
для всех кроме is_superuser или членов группы root.
Backend возвращает HTTP 403 при попытке POST. Просмотр истории операций
остаётся доступен всем. |
| Разрешить выбор услуги при ручной операции «Расход» | Показывает ссылку «+ Добавить услугу» в модалке Расхода. По умолчанию
выключено — большинству провайдеров привязка не нужна, операция остаётся
без FinanceOperations.usluga_id. |
| Максимальная сумма ручной операции (₽) | Защита от опечаток («9000» вместо «900») и фрода. Если задана —
backend отклоняет операции выше указанной суммы. 0 = без
ограничения. Не действует на автоматические процессы (Celery worker,
ЮKassa webhook, ОП). |
| Обязательное описание операции | Запрещает пустое поле «Описание». Полезно для аудита — при разборе спорных операций ясно за что списали. Backend возвращает HTTP 400 если описание пусто. |
| Разрешить удаление финопераций | Если выключено — иконка корзины скрыта в UI,
backend возвращает 403 на DELETE-запросы. Для отмены неправильной
операции остаётся только сторнирование (создание
парной обратной операции с пометкой storno=True) —
обе строки видны зачёркнутыми, что даёт полный аудит-trail для
бухгалтерии. |
Все ограничения проверяются и в backend (HTTP 403/400 на
endpoints finops_ajax, finops_crud_ajax,
FinOpChangeView) и в frontend (кнопки/ссылки/поля
скрыты в HTML).
Важно: ограничения касаются только ручных операций
через UI. Автоматические процессы — Celery worker
billing_worker для абонплаты, webhook ЮKassa, обещанный платёж,
auto-block по отрицательному балансу — работают как обычно, без проверок.
Это нужно чтобы политика «только суперюзер» не сломала автоматическое начисление.
Вкладка «Безопасность» — авторизация: FIDO2, reCAPTCHA, блокировка, сессии
Ниже блока «Финансовые операции» на странице /admin/settings/system/security/ расположены 4 блока управления безопасностью входа.

| Блок | Что делает |
|---|---|
Авторизация через FIDO2/WebAuthnSECURITY_WEBAUTHN_ENABLED |
Вход по passkey (YubiKey, Touch ID/Face ID, Windows Hello). После включения сотрудники привязывают ключ в Профиле (любой сотрудник, не только su; модель StaffWebAuthnCredential), клиенты — в ЛК. На странице входа в биллинг появляется кнопка «Войти по ключу (passkey)». |
Google reCAPTCHA v3RECAPTCHA_SITE_KEY / RECAPTCHA_SECRET_KEY |
После ввода обоих ключей появляются тумблеры «Авторизация в биллинге» (RECAPTCHA_ON_ADMIN_LOGIN) и «Авторизация в ЛК» (RECAPTCHA_ON_LK_LOGIN). |
Блокировка аккаунтаLOCKOUT_ENABLED |
Блокировка после неудачных попыток входа: число попыток (3/5/10), событие — «блокировать попытки на 1 час» или «блокировать аккаунт» (с настраиваемым сообщением). |
Сохранение сессииSESSION_PERSIST_ENABLED |
Срок хранения сессии (1ч … бессрочно) + чекбоксы «Для клиентов» / «Для персонала (кроме su)». При активации в формах входа появляется чекбокс «Запомнить меня». |
Все настройки в категории security, по умолчанию выключены. Миграция 0230 добавляет модель StaffWebAuthnCredential (passkey сотрудников).
Адаптивная шапка админки
Верхнее меню сжимается ступенями при нехватке ширины (только десктоп ≥768px), освобождая место без потери пунктов.

- Пункт «Продажи» переименован в «CRM».
- Ступень 0 — сворачивается левый сайдбар (ручной выбор пользователя не трогается).
- Ступень 1 — имя пользователя → фамилия, «Тарификация» → «Тарифы», «Справочники» → «Справ.».
- Ступень 2 — пункты Видео / IPTV / IP-телефония группируются в выпадающее меню «Услуги» (сразу после «Тарифы»).
- При расширении окна всё откатывается обратно.
Вкладка «Аудит» — настройки журнала действий по клиентам
Управление параметрами вкладки Аудит в карточке клиента и общим поведением логирования. Доступна по адресу /admin/settings/system/?tab=audit только пользователям группы root или с is_superuser=True.

| Параметр | Диапазон | Default | Что меняет |
|---|---|---|---|
Период по умолчанию (месяцев)AUDIT_TAB_DEFAULT_PERIOD_MONTHS |
1–60 | 12 | При первом открытии вкладки «Аудит» в карточке клиента сервер ставит диапазон [now − N мес .. now]. Пользователь может расширить вручную через datepicker. |
Записей на страницеAUDIT_TAB_PER_PAGE |
10–500 | 50 | Количество строк в таблице вкладки. Больше = меньше переключений страниц, но дольше первая загрузка. |
Максимум строк в CSV-экспортеAUDIT_CSV_EXPORT_LIMIT |
1 000 – 500 000 | 50 000 | Защита от перегрузки сервера при выгрузке. При превышении выгружаются последние N записей по дате (хвост обрезается). |
Скрывать системные событияAUDIT_TAB_HIDE_SYSTEM_EVENTS |
bool | off | Не показывать строки без оператора (Celery, billing_worker, авто-блокировки) во вкладке Аудит и в KPI-плитках. Полезно для операторов 1-й линии — меньше шума, легче найти действия людей. |
Все 4 настройки хранятся в таблице system_settings (category = audit), читаются через хелперы в billing/services/settings_service.py (get_audit_default_period_months(), get_audit_per_page(), get_audit_csv_export_limit(), is_audit_hide_system_events()) с clamp в коде на случай некорректного значения в БД.
Срок хранения записей аудита (по умолчанию 365 дней) настраивается отдельно в разделе Очистка БД — параметр DB_CLEANUP_AUDIT_DAYS. Это сделано чтобы retention-политика управлялась рядом с другими параметрами очистки (MSG_STACK, RADIUS_SESSIONS), а не дублировалась.
Быстрый переход в настройки: для пользователей с is_superuser=True в toolbar вкладки «Аудит» карточки клиента появляется иконка-шестерёнка справа от кнопки CSV-экспорта — клик ведёт прямо в /admin/settings/system/?tab=audit.

Вкладка «Логи» — хранение и уровень логирования
Управление файлами журналов в /var/log/django/: ротация, сжатие, уровень логирования Django и FreeRADIUS. Без ограничения по сроку хранения журнал FreeRADIUS на уровне trace вырастает до десятков гигабайт за месяц.
Параметры:
| Параметр | Диапазон | Default | Что меняет |
|---|---|---|---|
Срок хранения логов (дней)LOG_RETENTION_DAYS |
1–90 | 14 | Сколько дней logrotate хранит файлы. Применяется к error.log, freeradius.log, celery_*.log, gunicorn_*.log и др. Ротация раз в сутки в 00:00 на хосте. |
Уровень логирования DjangoLOG_LEVEL |
DEBUG / INFO / WARNING / ERROR | INFO | Влияет на error.log и celery_*.log. Применяется после перезапуска контейнеров. |
Verbosity FreeRADIUSFREERADIUS_DEBUG_LEVEL |
info / debug / trace | info | info — только Accept/Reject (~10 MB/сутки). debug (флаг -X) — детально (~100 MB/сутки). trace (флаг -xx) — полная трассировка (~800 MB/сутки, не использовать в проде). |
Сжимать ротированные файлы gzipLOG_COMPRESS |
bool | true | Архивы прошлых дней сжимаются (≈ ×10 экономия места). Чтение через zcat имя.gz. |
Справа на вкладке — таблица текущего размера всех файлов в /var/log/django/ с подсветкой больших (≥100 МБ оранжевый, ≥1 ГБ красный). Клик по имени файла → переход в просмотр содержимого (/admin/reports/dev/logs/).
Просмотр логов с подсветкой
Страница /admin/reports/dev/logs/ (раздел «Отчёты → Разработка и логи», только root-доступ) показывает 12 каналов журналов слева с текущим размером, справа — содержимое выбранного файла.

- Чтение с конца файла — функция
_tail_log()читает последние 500 строк, двигаясь от конца файла чанками, не загружая его целиком в память. Поэтому даже лог на десятки гигабайт открывается мгновенно (в шапке показано «Показано: 500 / N строк»). Это защищает от переполнения памяти при открытии многогигабайтногоfreeradius.log. - Подсветка по уровням (
colorizeLog) — каждая строка раскрашивается по содержимому: красный дляerror/traceback/exception, оранжевый дляwarning, серый дляdebug, обычный дляinfo. Цвета адаптируются под тёмную тему. - Кнопки: обновить, скачать файл, поделиться ссылкой (
?log=имя), очистить лог / очистить все логи (только суперадмин).
Ротация логов на сервере
Часть логов пишет Django через RotatingFileHandler (error.log,
radius.log, payment.log, sorm.log, staff.log —
maxBytes 10 МБ, backupCount 5, в просмотрщике видны как radius.log.1….5).
Но нативный freeradius.log пишет сам FreeRADIUS (C-side), и Django его
не ротирует. Если FreeRADIUS запущен в trace-режиме (-xx), этот файл растёт на
~5 ГБ/сутки — он однажды вырос до 43 ГБ.
Лечение:
- Уровень детализации FreeRADIUS задаётся переменной
RADIUS_DEBUG_LEVELв.env(читаетсяdocker/freeradius/entrypoint.sh):info(без флага, ~1 ГБ/сутки, только Accept/Reject и блокировки),debug(-x),trace(-xx, не использовать в проде). Если переменная не задана вовсе, контейнер стартует именно сtrace— на новой установке задайтеinfoявно. После правки —docker compose up -d --force-recreate freeradius. /etc/logrotate.d/smit-freeradius— ротация нативного лога (daily, rotate 5, maxsize 100M, compress,copytruncate— обязателен, т.к. FreeRADIUS держит файл открытым,su root root— т.к. каталог volume world-writable). Файл больше не превышает ~600 МБ./etc/cron.daily/smit-radacct-cleanup— удаляет accounting detail-файлыradacct/<NAS>/detail-YYYYMMDDстарше 14 дней (эти данные уже продублированы в таблицеRADIUS_SESSIONS).
Текущий размер каждого файла виден в просмотрщике — после фикса freeradius.log
держится в районе десятков мегабайт:

Вкладка «Скорость» — Gunicorn / Celery / БД / Throttling (переименована)
Параметры процессов и ресурсов. Изменения требуют перезапуска контейнеров (web, celery). 4 группы настроек 2×2 + статус-блок снизу.
| Группа | Параметры |
|---|---|
| Веб-сервер (Gunicorn) | GUNICORN_WORKERS (1–16, default 1), GUNICORN_THREADS (1–32, default 8), GUNICORN_TIMEOUT (30–600 сек, default 120). |
| Фоновые задачи (Celery) | CELERY_WORKER_CONCURRENCY (1–16, default 8 — не ставьте 16), CELERY_TASK_TIME_LIMIT (30–3600 сек, default 600). |
| База данных и кеш | DB_CONN_MAX_AGE (0–3600, default 0 — закрывать после каждого запроса; — фикс утечки соединений), REDIS_CACHE_TTL_DEFAULT (10–86400 сек, default 300), IP_POOL_STATS_CACHE_SECONDS (5–600, default 60). |
| Лимиты Mobile API | MOBILE_API_THROTTLE_RATE_USER (5–300 запросов/мин, default 30), MOBILE_API_THROTTLE_RATE_ANON (1–60 логинов/мин, default 5). |
Статус-блок снизу (read-only метрики, обновляется при загрузке страницы): CPU, RAM, Load average, PostgreSQL соединений (с алертом если >80%), размер БД, Celery очередь, Redis память.
Вкладка «RADIUS» — таймауты, retention, NAS auto-assign (переименована)
Параметры RADIUS-сессий, NAS-мониторинга и хранения истории. Применяются при следующей авторизации или ближайшем прогоне Celery beat (cleanup-stale-sessions каждые 5 минут, db-cleanup-daily в 03:00 UTC).
| Группа | Параметры |
|---|---|
| Активные сессии | SESSION_STALE_MINUTES (10–360, default 60) — после скольких минут без Update сессия считается зомби и LOGGED сбрасывается. ACCT_INTERIM_INTERVAL (60–3600 сек, default 600) — раз в сколько секунд NAS должен слать Accounting-Update. |
| Хранение истории | SESSIONS_RETENTION_DAYS (7–365, default 90), MSG_STACK_RETENTION_DAYS (7–365, default 30), AUDIT_RETENTION_DAYS (30–1825, default 365). Целевая task — db-cleanup-daily, чистка батчами по 5000 с паузой 100мс. |
| Авто-замена NAS | DEFAULT_NAS_ID (dropdown enabled NAS) — приёмник для новых клиентов. AUTO_ASSIGN_NAS_MINUTES (1–1440, default 3) — через сколько минут после первой авторизации перевешивать на реальный NAS. NAS_RESYNC_MINUTES (5–120, default 15) — окно для beat-задачи nas-resync-recent которая реагирует на ручную правку оператора. |
| CoA / Disconnect | COA_TIMEOUT_SECONDS (1–60, default 10) — timeout для radclient при CoA Disconnect. |
Статус-блок снизу: NAS всего / UP / DOWN (если есть), Сейчас онлайн (LOGGED), Активных RADIUS-сессий, Расхождение, размер таблиц RADIUS_SESSIONS / AUDIT_OPERATIONS / MSG_STACK.
Вкладка «Сообщения клиентам» — политика уведомлений
Единая страница для управления всеми каналами доставки сообщений: Email, SMS, Push, Telegram, VK. Объединяет настройки из 4 разных мест в одну ментальную модель оператора («Сообщения»). 4 группы 2×2 + статистика снизу.
| Группа | Параметры и эффект |
|---|---|
| Тихий час | NOTIFY_QUIET_HOURS_START / NOTIFY_QUIET_HOURS_END (HH:MM). В заданное окно SMS и push не отправляются (Email и Telegram приходят молча). Окно может пересекать полночь (например 22:00–08:00). Fallback на старые MOBILE_PUSH_QUIET_HOURS_* для совместимости. |
| Низкий баланс | LOW_BALANCE_NOTIFY_DAYS_BEFORE (1–14, default 3) — за сколько дней до окончания баланса предупреждать. LOW_BALANCE_NOTIFY_THRESHOLD_RUB (0–10000 руб, default 100) — дополнительный триггер по сумме. |
| Каналы (kill-switch'и) | 5 toggle: NOTIFY_EMAIL_ENABLED, NOTIFY_SMS_ENABLED, NOTIFY_PUSH_ENABLED, NOTIFY_TELEGRAM_ENABLED, NOTIFY_VK_ENABLED. Внимание: выключение канала останавливает ВСЕ сообщения через него, включая восстановление пароля и OAuth. |
| Антидубль / шаблоны | NOTIFY_DUPLICATE_WINDOW_MIN (0–1440, default 60) — не слать одинаковое сообщение чаще раза в N минут (дедуп через Redis по md5 head_txt). EMAIL_DEFAULT_SUBJECT (строка до 200 симв.) — подставляется в письма без явного subject. MSG_RETRY_COUNT (1–10, default 4) — попыток отправки при ошибках шлюза. |
Подключение: billing/services/notification_policy.py::should_send(channel, abonent_id, head_txt) вызывается в billing/tasks/messaging.py:_dispatch_message для каждого канала. Пропущенные сообщения логируются в MsgStack.sms_status='skipped' с sms_error=причина — оператор видит почему сообщение не доставлено.
Шлюзы каждого канала настраиваются в отдельных разделах: Email /admin/settings/email/, SMS /admin/settings/sms/, Push /admin/settings/firebase/. Здесь — общая политика на уровне всей системы.
Статистика снизу: отправлено сегодня по каналам, в очереди, SMS-ошибки, SMS-пропуски (тихий час / дубль), бейдж «Тихий час сейчас».
Доступ суперпользователя — 2FA, IP-ограничение, политики паролей
В правой колонке вкладки Безопасность — карточка
«Доступ суперпользователя». Все политики применяются
только к is_superuser и по умолчанию выключены
(поведение входа не меняется, пока администратор не включит их осознанно).
Управление доступно только суперпользователю.
| Политика | Настройка | Что делает |
|---|---|---|
| Доступ su только с разрешённых IP | SU_RESTRICT_BY_IP + SU_ALLOWED_IPS |
Вход su разрешён только с IP из списка (через запятую, CIDR). Кнопка «мой IP» подставляет текущий адрес. С недоверенного IP — HTTP 403. Fail-open при пустом списке (защита от self-lockout). |
| Обязательная 2FA для su | SU_REQUIRE_2FA |
TOTP (Google Authenticator / Authy). Подключается в профиле
(/admin/settings/profile/) — QR-код + 10 одноразовых
backup-кодов. Без 2FA вход блокируется до её настройки. |
| Спрашивать 2FA, если IP вне списка | SU_2FA_IF_IP_OUTSIDE |
С доверенного IP — вход без кода; с прочих — запрос TOTP. Удобно для быстрого входа из офиса и защищённого — извне. |
| Требовать сложный пароль | SU_REQUIRE_STRONG_PASSWORD |
При смене пароля su: 8+ символов, буква + цифра + спецсимвол. Слабый пароль отклоняется с пояснением. |
| Смена пароля при первом входе | SU_FORCE_PASSWORD_CHANGE_FIRST |
Если у su стоит флаг «требуется смена» — при входе принудительный редирект в профиль на смену пароля. |
| Смена пароля каждые X дней | SU_PASSWORD_MAX_AGE_DAYS |
Отслеживается дата последней смены. Если пароль старше X дней — при
входе принудительная смена. 0 = без ограничения. |
Двухфакторная аутентификация (TOTP). Подключение в профиле:
сканируете QR-код приложением-аутентификатором, подтверждаете кодом — 2FA
активна. При активации выдаются 10 резервных кодов (формат
XXXX-XXXX, показываются один раз) — на случай потери телефона.
При входе после логина/пароля запрашивается 6-значный код (можно ввести
backup-код). Отключить 2FA нельзя, пока включена политика «Обязательная 2FA».
Защита от self-lockout: все политики выключены по умолчанию;
backup-коды 2FA; IP-список fail-open при пустоте; аварийный сброс через консоль
сервера (set_setting('SU_REQUIRE_2FA', False)). Каждое изменение
политик пишется в AuditOperations.
Подключение: billing/services/su_security.py (логика IP/2FA/паролей),
billing/views/auth.py (вход), billing/views/profile.py
(2FA + смена пароля).

Вкладка «Блокировки и финансы» — captive-portal + бизнес-правила
Управление блокировкой клиентов за долг и базовыми правилами биллинга. 4 группы 2×2 + статус блокировок. Закрывает давнюю боль «Не авторизовать по RADIUS при отрицательном балансе» и задачу №4 Марии (captive-portal).
| Группа | Параметры и эффект |
|---|---|
| Captive Portal (мягкая блокировка) | BLOCK_POOL_ID (dropdown пулов) — IP-пул для walled-garden (обычно отдельный private-диапазон типа 10.88.0.0/24). BLOCK_FILTER_ID (default walled_garden) — атрибут Filter-Id в RADIUS-ответе, привязан к firewall-правилу на NAS. BLOCK_PORTAL_URL — справочный URL nginx-заглушки (для копирования в nginx config). |
| Правила блокировок | 🚨 Аварийный kill-switch «Разрешить интернет всем клиентам» — игнорирует ВСЕ блокировки в RADIUS (даже b_admin). «Разрывать сессию при переходе в b_negbal» (default ON) — сразу CoA Disconnect, иначе текущая сессия доживает до Acct-Interim. «Не авторизовать по RADIUS при отрицательном балансе» — hard REJECT vs soft walled-garden. |
| Биллинг | BILLING_CHARGES_HOUR (0–23, default 9) — час суток для ежедневных списаний billing_worker. Рекомендация: 3 (ночь) — клиенты не будут видеть «минус» во время пользования. «Списывать у отключённых» (default ON) — копит долг даже у enabled=False; OFF — не списываем. «Отсрочка блокировки юр.лиц» LEGAL_BLOCK_DELAY_DAYS (0–365, default 0) — через сколько дней блокировать юридическое лицо при отрицательном балансе. 0 = блокировать сразу (как физлиц). При значении >0 клиент с признаком «Юр. лицо» блокируется только если баланс держится в минусе указанное число дней подряд; физлица отсрочкой не затронуты. Дата ухода в минус хранится в AdminAccounts.NEGATIVE_SINCE, сбрасывается при пополнении до неотрицательного баланса. |
| Отображение FinanceOperations | «Скрыть операции с нулевой суммой» — фильтрует op_summa=0 в /admin/Abonents/FinanceOperations/ и карточке клиента. Не влияет на хранение в БД. |
Подключение: billing/services/block_policy.py в 4 точках кода — radius_python/internet.py:authorize() (kill-switch ДО soft-block), billing/models/abonents.py:block() (пропуск CoA), billing/tasks/billing_worker.py:_process_service() (skip списания), billing/views/finops_list.py (queryset filter).
Статус-блок снизу: Активных / Заблокированных клиентов, по b_negbal / b_admin / b_own, активных Обещанных Платежей, заблокировано/разблокировано сегодня. Большой красный alert над формой если включён аварийный kill-switch.
Вкладка «Прокси» — пул прокси для Telegram и Нейросети
Из России api.telegram.org и внешние API AI-провайдеров недоступны — биллинг ходит к ним через прокси. Раздел Настройки системы → Прокси (/admin/settings/system/proxy/) — единый пул прокси с ролями, авто-проверкой и журналом. Заменил прежний блок «Прокси для Telegram» из Интеграций (старые плоские ключи остаются как fallback).
Управление прокси — на сервере лицензий. Пул прокси теперь ведётся централизованно на сервере лицензий (один пул на все инсталляции — прокси меняются в одном месте, все биллинги подхватывают). Биллинг получает пул по лицензионному ключу (GET /api/gw/proxies/) и зеркалит его в свою таблицу. На странице «Прокси» такие прокси помечены значком облака ☁ и редактируются только на сервере лицензий; кнопка «Синхронизировать» подтягивает изменения сразу. При недоступности сервера лицензий биллинг продолжает работать с последним полученным пулом (offline-safety). Локально добавленные прокси (без облака) остаются как аварийный fallback.

Как работает выбор прокси (fallback):
get_api_proxies(role)
→
Первый живой прокси пула с нужной ролью (по приоритету)
→ если пул пуст →
старые ключи TELEGRAM_PROXY_*
→ если выкл →
прямое подключение (None)
Переключатель «Использовать прокси»
Глобальный тоггл сверху. Выключен → get_api_proxies() возвращает None, Telegram/Нейросеть подключаются напрямую (настройка PROXY_ENABLED в БД). При выключении форма/таблица/журнал скрываются.
Добавление прокси
Список прокси по одному на строку. Поддерживаемые форматы: ip:port:login:password, login:password@ip:port, ip:port (без авторизации). Тип — Авто-определение (по умолчанию; живая проба HTTP→SOCKS5), HTTP или SOCKS5. Роли — «для Telegram» / «для Нейросети» (можно обе). При добавлении параллельно определяется тип и геолокация по IP (ip-api.com). Прокси добавляется всегда, даже если автопроверка не достучалась — со статусом 🔴 и подсказкой (например провайдер отвечает 407 при неверных кредах / IP-binding).
Таблица «Прокси-серверы»
Колонки: Тип (бейдж HTTP/SOCKS5), Адрес (ip:port, иконка-ключ + тултип логин/пароль), Гео (флаг страны + город), Роли (TG / Нейросеть), Статус (🟢 доступен · 🔴 недоступен · ⚪ не проверялся, с латентностью в тултипе), Приоритет, Ред (kebab-меню действий). Действия в kebab: Проверить, Включить/Выключить, Назначить роль (Только Telegram / Только Нейросеть / Обе), Удалить.

«Проверить все» — проверяет все прокси и расставляет приоритеты: живые по возрастанию задержки (быстрый = приоритет 1), мёртвые в конец. Если есть нерабочие — кнопка превращается в «Удалить нерабочие (N)».
Автопроверка и уведомления
Celery beat proxy-pool-check проверяет пул каждые PROXY_CHECK_INTERVAL_MIN минут (default 60). При переходе прокси в недоступное состояние и при полном отсутствии живых прокси для роли — Telegram-алерт (тоггл PROXY_ALERTS_ENABLED). События пишутся в Аудит (добавление/удаление — с указанием кто, системное «нет доступных прокси»).
Журнал событий
Правая колонка — последние 50 событий (проверки, переходы up/down, добавление/удаление) с авто-обновлением каждые 30с. Кнопка «Скачать» выгружает журнал в CSV (до 1000 записей).

Тёмная тема и работа с телефона поддержаны. Потребители прокси (Telegram-рассылки, AI-чаты ЛК/мобильного, геокодер и др., ~18 точек) используют пул автоматически через get_api_proxies().
6.2. Шаблоны печати
Шаблоны документов — договоры, акты, квитанции. Шаблон — это HTML или Word-файл
с подстановочными переменными вида {{ contract_number }},
{{ abonent.name }}, {{ tariff }}. Готовый документ
генерируется при печати из карточки клиента.

6.3. Фискализация (54-ФЗ)
Автоматическая отправка кассовых чеков в ОФД: модуль фискализации, какие платежи фискализируем, чек-лист готовности и очередь чеков.
6.3.1. Модуль фискализации 54-ФЗ
Модуль формирует кассовый чек и передаёт его в ОФД при приёме оплаты — согласно Федеральному закону № 54-ФЗ. Чек бьётся собственной кассой организации, реквизиты продавца (ИНН, СНО, ставка НДС) берутся из брендинга компании — единый источник, без дублирования в карточке кассы.
Зачем нужен модуль, какие платежи фискализируем и почему агрегаторы мимо, чек-лист готовности к боевому режиму, карточка кассы и очередь чеков. С озвучкой.
Чек бьём только по своему безналу
Платёжные агрегаторы — ЮKassa, Wallet One — фискализируют оплату своей кассой сами. Если пробить чек ещё и нашей, клиент получит два чека на один платёж, а в ФНС уйдёт двойная выручка; исправляется это только чеками коррекции через налоговую. Поэтому модуль фискализирует только безнал, который мы обрабатываем сами — через банковские выписки.
Какие платежи фискализируем
Настройка на странице фискализации — чипы источников. Отмеченный источник попадает в очередь чеков, снятый не попадает в неё вовсе.

| Источник | Кто пробивает чек | По умолчанию |
|---|---|---|
| Банковская выписка | мы | отмечен |
| ЮKassa, Wallet One, платёжная система | агрегатор | снят |
| Ручная проводка, обещанный платёж, периодические списания | — | снят |
Правило действует в двух местах и обойти его через интерфейс нельзя: операция чужого источника не попадает в очередь, а кнопка «Пробить чек» в карточке операции откажет с пояснением. Пустой список источников означает «все» — это путь отката к прежнему поведению.
Почему источник определяется, а не хранится
В финоперации нет отдельного столбца «источник»: откуда пришли деньги, видно по
совокупности признаков — служебному полю оператора, меткам в описании
([bank_op:N], [txn:…]), типу операции и услуге. Эвристика
собрана в одном месте, поэтому иконка в списке операций и решение о чеке всегда
совпадают. У онлайн-оплат поле оператора пустое — они узнаются по названию системы в
описании и по типам операций «Оплата через платежные системы» и «ЮKassa».
Параметры чека — что указывать
Блок на странице фискализации задаёт, что попадёт в чек и как модуль его отправляет. Значения ниже — рекомендация для провайдера, который фискализирует пополнения счёта из банковских выписок.
| Поле | Что указать | Почему |
|---|---|---|
| Наименование позиции в чеке (тег 1030) |
Пополнение лицевого счёта, договор {договор} |
Пополнение счёта — это аванс за услуги связи, обобщённая формулировка
корректна по 54-ФЗ. Поддерживает плейсхолдеры (см. ниже):
{договор} подставит номер договора клиента, {фио} — его ФИО.
Так формат совпадает с чеком платёжного агрегатора. Пусто → подставится
«Услуги связи / доступ к сети Интернет». До 128 символов. |
| Имя позиции из услуги клиента (чек-бокс) | снять | Ставит в чек название услуги клиента, но только если она привязана к операции. У зачислений из банковских выписок услуги нет, поэтому чек всё равно возьмёт общий текст выше — чек-бокс ничего не изменит. Включать имеет смысл, только когда фискализируются начисления за конкретные услуги. |
| Контакт в чек | e-mail (или телефон) | Куда отправить электронный чек клиенту. Если у клиента нет e-mail — используется телефон, иначе e-mail кассы по умолчанию. |
| Типы операций для чека | оставить пустым | Пусто = разумный набор по умолчанию (все приходы реальных денег, кроме
служебных списаний и обещанного платежа). Источник платежа уже ограничен
настройкой «Какие платежи фискализируем», поэтому жёсткий список типов не нужен.
Если указать — фискализируются только эти op_type (для банковских
выписок это тип 1041). |
| Попыток отправки / Опрос ОФД, мин / Алерт застрявших, ч | 5 / 5 / 6 (по умолчанию) | Сколько раз повторять отправку при сбое ОФД, как часто опрашивать статус и через сколько часов застрявшего чека слать Telegram-алерт. |
Плейсхолдеры в наименовании позиции
Поле «Наименование позиции в чеке» — это не просто статичный текст: в него можно вставить плейсхолдер, и модуль подставит данные конкретной операции при пробитии чека. Так наименование получается персональным для каждого клиента, а не одинаковым на всех чеках.
| Плейсхолдер | Что подставится |
|---|---|
{договор} | Номер договора клиента (contract_number). Синонимы: {contract}, {номер договора}, <номер договора> |
{фио} | ФИО / название клиента. Синонимы: {name}, {абонент} |
- Пример: шаблон
Пополнение лицевого счёта, договор {договор}на чеке превращается в «Пополнение лицевого счёта, договор 1484». - Если у операции нет договора, плейсхолдер убирается, а лишние пробелы схлопываются (не остаётся «висящего» слова).
- Подстановка работает и когда наименование берётся из услуги клиента (чек-бокс «Имя позиции из услуги клиента») — плейсхолдер в названии услуги тоже раскроется.
- Итоговая длина обрезается до 128 символов (тег 1030).
Готовность к боевому режиму
Главный выключатель FISCAL_ENABLED по умолчанию выключен: чеки в ОФД не
уходят. Включить его напрямую нельзя — тумблер ведёт в чек-лист, и пока обязательные
пункты не выполнены, кнопка «Включить боевой режим» заблокирована. Сервер проверяет то
же самое: запрос на включение мимо интерфейса будет отклонён.

| Пункт | Блокирует включение | Что означает |
|---|---|---|
| Касса с поддерживаемым типом | да | тип «Другая» драйвера не имеет |
| Логин, пароль и группа ККТ | да | без них ОФД не примет ни одного чека |
| Связь с ОФД проверена | да | результат проверки живёт 5 минут |
| Задан ИНН продавца | да | берётся из реквизитов компании |
| ИНН кассы совпадает с ИНН компании | нет | в чек уйдёт ИНН компании; расхождение обычно означает опечатку |
| Выбраны источники и типы операций | нет | пусто = разумный набор по умолчанию |
Очередь чеков
Раздел Отчёты → Очередь чеков (/admin/reports/fiscal_queue/)
показывает, что именно ждёт отправки. Раньше состояние очереди было видно только строкой
счётчиков в настройках, без возможности посмотреть содержимое.
Список построен на единых компонентах: строки подгружаются по мере прокрутки (бесконечная загрузка), действия строки собраны в компактное меню, клик по имени клиента открывает боковую карточку клиента, а на телефоне строки превращаются в карточки с подписями полей. Период задаётся единым выбором дат с пресетами. Клик по имени клиента открывает боковую карточку абонента и сразу прокручивает к блоку «Банк» с его платежами из выписок.

- Состояния — «ждут отправки», «ждут ответа ОФД», «с ошибкой», «пробиты», со счётчиками; те же счётчики на странице настроек стали ссылками сюда.
- Фильтры — период, поиск по клиенту, договору, номеру операции и тексту ошибки.
- Колонка «Источник» — откуда платёж; у выключенных источников подпись зачёркнута.
- Отправка — по одной операции (сразу с ответом ОФД) или пачкой через очередь. Каждая отправка требует подтверждения (чек уходит в ОФД и ФНС) и пишется в журнал аудита. Отправлять может тот, у кого есть право на финансовые настройки.
- Защита отправленных — у операций, чек по которым уже ушёл («ждёт ОФД», «пробит»), меню действий не показывается: повторная отправка означала бы дубль чека в ОФД. Вместо него — прямая ссылка на электронный чек, а у даты на мобильном стоит зелёная галочка «отправлен».
- Значок песочных часов — операция старше порога автоматической досылки; автоматика такие не трогает.
- Убрать из очереди (корзина в строке или массово) — снимает операцию с фискализации: чек по ней не пробьётся, но само движение денег остаётся. Уже пробитые чеки не затрагиваются — в ОФД по ним лежит фискальный документ, его нельзя «удалить», для отмены нужен чек возврата.
- Отчёт в Telegram — кнопка в шапке шлёт сводку в Telegram-группу: пробито за сутки и на какую сумму, сколько ждёт отправки, ошибки. Тот же отчёт уходит автоматически раз в сутки, если включён (настройка «Отчёт в Telegram», час — «Час отправки отчёта»; канал — «chat_id группы», по умолчанию общий админ-чат).

Как работает (поток чека)
flowchart LR A["Приём оплаты
банковская выписка"] --> B{"Источник
подлежит?"} B -->|"нет — агрегатор"| X["Пропуск: чек бьёт
ЮKassa / Wallet One"] B -->|"да — свой безнал"| C["Движок:
состав чека 54-ФЗ"] C --> D["Очередь чеков"] D --> E["АТОЛ → ОФД"] E -->|"done"| F["Чек клиенту
e-mail / SMS / ЛК"] E -->|"fail"| G["Авто-повтор →
Telegram-алерт"]
- Приём оплаты — зачисление банковской выписки создаёт финоперацию.
- Движок проверяет источник, сумму и тип операции, собирает состав чека по 54-ФЗ и ставит задачу в очередь.
- Очередь отправляет чек в ОФД, опрашивает статус, повторяет при сбоях и шлёт Telegram-алерт на застрявшие чеки.
- Чек клиенту — электронный чек на e-mail или телефон, ссылка в личном кабинете и в мобильном приложении, фискальные реквизиты в карточке операции.
Статусы чека
- Ждёт отправки — операция помечена к фискализации.
- Ждёт ответа ОФД — чек ушёл, ОФД обрабатывает; статус опрашивается периодически.
- Пробит — чек зарегистрирован, сохранены № ФД, ФП и ссылка на чек.
- Ошибка — ОФД отклонил или недоступен; авто-повтор до N попыток, затем Telegram-алерт.
Старые операции автоматика не досылает
Досылаются только свежие — не старше порога FISCAL_PENDING_MAX_AGE_DAYS
(по умолчанию 3 дня). По 54-ФЗ чек пробивается в момент расчёта; пробить пачку чеков
задним числом — решение бухгалтерии, а не побочный эффект включения тумблера. Такие
операции остаются в очереди и отправляются вручную.
Касса (доступ к ОФД)
Параметры доступа вводятся в карточке кассы: тип кассы, URL сервера ОФД, группа ККТ, логин и пароль, организация, ИНН, место расчётов, система налогообложения, e-mail продавца и флаг тестового сервера.

- Организация — чей чек пробивает касса. По 54-ФЗ касса привязана к ИНН юрлица, поэтому у каждой организации должна быть своя. Касса без организации служит запасной для тех, у кого своей нет. Реквизиты продавца (название, ИНН, НДС) правятся в карточке организации на вкладке «Реквизиты» — карандаш рядом со строкой реквизитов ведёт туда напрямую.
- Боевой режим кассы и источники кассы — у каждой кассы свой выключатель и свой набор источников. По умолчанию касса наследует общие настройки; можно переопределить, когда у разных организаций разный статус.
- ИНН — 10 цифр для юрлица, 12 для ИП; должен совпадать с ИНН компании, иначе чек-лист покажет расхождение.
- Место расчётов — тег 1187. Для расчётов через интернет туда идёт адрес сайта, зарегистрированного в ОФД, а не улица.
- Пароль — наружу не отдаётся: карточка показывает только факт «задан». Пустое поле при сохранении означает «не менять».
- Ставка НДС — в карточке кассы её нет: она берётся из реквизитов компании, единым источником для всех чеков.
В списке касс колонка «Состояние» показывает, чего кассе не хватает («нет: логин, пароль, группа ККТ») или что ИНН расходится с компанией — без открытия карточки.
Боевой режим: общий и по кассе
Чек уходит в ОФД, только когда включён и общий рубильник
(FISCAL_ENABLED), и боевой режим кассы организации платежа.
Касса без явного флага наследует общий — так одна касса работает как раньше, а у
нескольких организаций режим и источники независимы.
flowchart TD
S{"Общий рубильник
FISCAL_ENABLED"} -->|"выключен"| N["Чек не уходит"]
S -->|"включён"| K{"Режим кассы
организации"}
K -->|"наследует общий"| Y["Чек уходит в ОФД"]
K -->|"включён"| Y
K -->|"выключен"| N
Права и журнал
- Страница фискализации, сохранение настроек и проверка связи закрыты правом «Настройки · Финансы».
- Список касс, выпадающий список компаний и счётчики очереди показывают только те организации, которые доступны сотруднику.
- Включение и выключение боевого режима, правка и удаление касс пишутся в журнал аудита с перечнем изменений.
Чек в карточке операции
На странице Финансовые операции в карточке есть секция «Чек» со статусом ОФД, номером ФД/ФП и ссылкой на электронный чек. Клиент видит ссылку на чек в личном кабинете и в мобильном приложении.
Налогообложение
При работе на УСН без НДС в чек передаётся признак «НДС не облагается». Ставка НДС и система налогообложения берутся из реквизитов компании (Брендинг); при переходе на ОСН переключатель ставки уже готов.
6.4. Платёжные системы
Настройка приёма онлайн-платежей: через что клиент платит из личного кабинета и мобильного приложения, какая берётся комиссия и с каких адресов принимается webhook.
Как настроить приём онлайн-оплат: общие настройки и кассы организаций, активная система и комиссия, секретные ключи, проверка подключения, безопасность вебхука и работа с телефона.

Наборы настроек: общие и кассы организаций
Страница правит два разных набора, между ними переключает полоса в шапке:
- Общие настройки — глобальные ключи. По ним платят клиенты организации по умолчанию и все, у кого организация не проставлена.
- Касса организации — собственные реквизиты приёма оплат конкретного
юрлица (
OrgPaymentSettings). При создании платежа биллинг сначала берёт кассу организации клиента и только при её отсутствии откатывается на общие ключи.

Если хотя бы у одной организации настроена своя касса, в общем режиме показывается предупреждение со ссылками на эти кассы: правки в общих настройках на их клиентов не влияют. Тумблер «Использовать свою кассу» выключает переопределение — клиенты организации возвращаются на общие ключи.
Что остаётся общим для всех организаций
Активная платёжная система, комиссия, валюта W1, секрет подписи Generic/UCS и белый список IP. На уровне организации переопределяются только реквизиты кассы, адреса возврата клиента и расчётный счёт приёма оплат.
Секретные ключи
Секреты в браузер не отдаются: в поле показывается только маска с опознавательным хвостом
(••••••••2bc9). Пустое поле при сохранении означает «не менять» —
чтобы заменить ключ, введите новый.

Проверка подключения
Кнопка «Проверить подключение» различает три исхода, а не два:
| Статус | Что значит |
|---|---|
| ✓ зелёный | Ключ подтверждён сервером платёжной системы (ЮKassa REST API v3, запрос /v3/me). |
| ⚠ жёлтый | Конфигурация заполнена, но протокол не позволяет проверить ключ запросом — старый HTTP-протокол ЮKassa и Wallet One. Работоспособность подтверждается только тестовым платежом. |
| ✕ красный | Отказ: неверные учётные данные, недоступен узел, не заполнены обязательные поля. |

Проверку можно выполнить для любой системы, в том числе неактивной — переключать боевой приём платежей для этого не нужно. Неактивная система помечается пунктирной рамкой и бейджем «не активна», её поля остаются читаемыми и доступными для правки.
Провайдеры
- ЮKassa (REST API v3) — современный API, рекомендован.
Параметры: shopId, secret key (формат
live_XXXилиtest_XXX), webhook URL (привязывается в личном кабинете ЮKassa). - ЮKassa HTTP — старый протокол на форме POST. Параметры: shopId, scid, shopPassword. Используется только для legacy-договоров.
- Wallet One (W1) — альтернативный провайдер. Параметры: merchant ID, secret key, валюта (643 = RUB), URL успеха и ошибки.
- Универсальный webhook — единый endpoint
/lk/payments/webhook/, который принимает все форматы (W1, ЮKassa HTTP, ЮKassa REST v3, Generic) и зачисляет на счёт.
Комиссия
Задаётся в процентах (например, 4,5), максимум 20 %; значение
проверяется на сервере. Комиссия добавляется клиенту сверху: при пополнении на 500 ₽ и ставке
4,5 % платёжная система спишет 522,50 ₽, а на счёт зачислится ровно 500 ₽. Карточка справа
пересчитывает пример при вводе.
Безопасность webhook

- Белый список IP (CIDR через запятую) — запросы с других адресов получают 403. Пустой список означает набор по умолчанию: ЮKassa, W1 и localhost. Кнопки-пресеты добавляют адреса без дублей, «Очистить» запрашивает подтверждение.
- Секрет подписи Generic/UCS — обязателен для приёма через «Единую кассу». Пока он не задан, канал помечается бейджем «не задан — канал отключён», а webhook отвечает 403. Кнопка «Генерировать» создаёт секрет криптостойким генератором браузера.
Аудит и сохранение
Каждое изменение пишется в журнал аудита (PAYMENT_SETTINGS) с автором и
перечнем изменённых параметров: для обычных полей — старое и новое значение, для секретов —
только факт замены. Кнопка «Сохранить настройки» закреплена внизу формы, не исчезает после
сохранения и снова гаснет, когда изменений нет. Перезапуск сервера вынесен отдельной кнопкой
и требует подтверждения.
Подробное описание API — на отдельной странице
Endpoints, схемы платежей, REST API v3 / HTTP, Wallet One, Mobile API — в разделе API, секция Платёжные API.
Маппа платёжных систем → FinTypes
При успешном платеже webhook (lk/services/payment.py::_credit_abonent) создаёт FinanceOperations с типом операции, выбираемым по pay_system. Маппа настраивается через /admin/dictionary/FinTypes/ + ключи SystemSettings:
| pay_system | SystemSettings ключ | FinTypes по умолчанию |
|---|---|---|
YooKassa | LK_PAYMENT_OPTYPE_YOOKASSA | «ЮKassa» (приход +1) |
W1 | LK_PAYMENT_OPTYPE_W1 | «Wallet One (W1)» (приход +1) |
card | LK_PAYMENT_OPTYPE_CARD | type_id=40 «Платёж с карты» |
generic / fallback | LK_PAYMENT_OPTYPE_GENERIC | type_id=23 «Оплата через платежные системы» |
Зачем это нужно: у каждой платёжной системы свой FinTypes, и бухгалтерия разделяет источники — отчёты «итого через ЮKassa за месяц» работают через простой фильтр по op_type_id без парсинга поля descr.
Как изменить:
- Создать новый тип в Справочники → Типы фин. операций (например, «СБП» или «T-Bank»).
- Установить
SystemSettings.valueдля соответствующего ключа =type_idнового типа. Через/admin/settings/system/или management-командуset_system_setting LK_PAYMENT_OPTYPE_YOOKASSA 51. - Webhook автоматически подхватит новое значение при следующем платеже (без рестарта).
Старые операции (под type_id=23) не переразмечаются — они остаются в истории под прежним типом. Только платежи, начисленные после миграции 0115, получают новые типы. Это безопасно: отчёты с интервалом «после 2026-05-08» получат правильную разбивку, ранние периоды останутся как есть.
6.4.1. Банковские выписки (автообработка)
Как разбирать поступления по безналу: очередь платежей, привязка платежа к клиенту, сводные реестры приёмщиков платежей, вкладка «Банк» в карточке клиента и работа с телефона.
Модуль автоматического приёма и зачисления платежей из банковских выписок. Письма с CSV/TXT-вложениями приходят на собственный почтовый ящик bank@вашдомен.ru (на почтовом сервере компании), парсер раскладывает операции в очередь модерации, matching сопоставляет с клиентами по 4 стратегиям (ИНН/лицевой счёт/назначение/fuzzy), оператор подтверждает или система автоматически зачисляет high-confidence матчи. Для юр.лиц генерируются PDF счёт-фактуры и акты (WeasyPrint), опционально загружаются в GCS и отправляются клиенту на email через noreply@вашдомен.ru.
Полная карта URL:
/admin/settings/bank_statements/— настройки модуля/admin/settings/bank_statements/parsers/— «Банки и парсеры»/admin/finance/bank_queue/— очередь модерации/admin/finance/bank_imports/— журнал импортов
Архитектура (8 фаз)
- SmitMailServ на demo-сервере сервер приложения — 4 ящика (bank/noreply/info/support) на почтовом поддомене, MX/SPF/DKIM/DMARC в cloudns.net
- IMAP-приёмник (
billing/services/imap_client.py) — Celery beatbank-statements-pullежечасно, реально работает в час/минуту изBANK_PULL_SCHEDULE_HOUR/MINUTE(default 6:00) - Парсеры (
billing/services/bank_parsers/) —sber.py(TXT, cp1251, разделитель;),alfa.py(CSV, cp1251, разделитель\t),dispatcher.pyопределяет формат по filename + первым байтам - Matching (
bank_matching.py) — 4 стратегии в порядке приоритета:inn→account→purpose→fuzzy(отключаем для prod). AmbiguousMatch исключение если несколько кандидатов — операция уходит в очередь модерации - Credit (
bank_credit.py) —transaction.atomic+select_for_updateна AdminAccounts, kill-switchBANK_AUTO_CREDIT_ENABLED(default OFF), auto-unblockb_negbalпри ostatok ≥ 0 - PDF счёт+акт (
bank_documents.py, WeasyPrint) — атомарная нумерация СЧ-2026-NNNN/АКТ-2026-NNNN через BankDocumentCounter, опциональная GCS-загрузка, учёт per-abonent настроек (send_act,auto_account,next_auto_acount) - Уведомления (
bank_notifications.py) — Telegram-сводка по unmatched с anti-spam (cache 24h) + email клиенту с PDF-attached (до 8MB) - Admin UI — четыре страницы раздела
Главная страница настроек

Структура страницы:
- Tab-навигация: «Общие настройки» ↔ «Банки и парсеры»
- Статистика: hero-карточка «В модерации» — кликабельная (ведёт на
?status=manual_review), красный фон если >50; остальные 4 KPI (Импортов/За сегодня/Операций/Зачислено) — компактные - Главный выключатель
BANK_AUTO_CREDIT_ENABLED— отдельной карточкой full-width. По умолчанию ВЫКЛ — модуль обрабатывает выписки и наполняет очередь модерации, но НЕ создаёт FinanceOperations - Дополнительные тогглы с цветовой меткой: 🟢 safe (auto_generate_docs, send_email_to_abonent), 🔴 danger (fuzzy_match с явным предупреждением «может ошибочно сопоставить»)
- Расписание (час+минута), день месяца отправки акта, GCS toggle, кнопки «Счёт»/«Акт» предпросмотра (модалка с iframe PDF)
- IMAP-приёмник (host/port/user/password/folder/SSL + whitelist) — кнопка «Проверить» с inline-результатом
- Telegram-алерты — поле «Ссылка на чат» парсит
https://t.me/c/<chat_id>/<thread_id>или@usernameи заполняет chat_id + thread_id + название
Все тогглы (детальное описание)
| Ключ | Default | Назначение |
|---|---|---|
BANK_AUTO_CREDIT_ENABLED | false | Главный kill-switch автозачисления. Без него модуль работает в режиме «модерация-только» |
BANK_AUTO_GENERATE_DOCS | false | Авто-генерация PDF счёт+акт после credit (только для юр.лиц) |
BANK_EMAIL_TO_ABONENT | false | Отправлять email клиенту со ссылкой/PDF attached |
BANK_NOREPLY_FROM | noreply@вашдомен.ru | FROM-адрес для писем клиентам |
BANK_TG_ALERT_ENABLED | true | Telegram-сводка по unmatched-платежам |
BANK_TG_ALERT_CHAT_ID / BANK_TELEGRAM_ALERT_CHAT_ID | — | Chat ID (priority: TG_ → TELEGRAM_); thread_id опционально |
BANK_TG_ALERT_MIN | 1 | Минимум pending для алерта |
BANK_PULL_SCHEDULE_HOUR/MINUTE | 6/0 | Час+минута ежедневного забора писем (Celery beat ежечасно с фильтром ±10мин) |
BANK_DOC_DEFAULT_SEND_DAY | 0 | День месяца отправки акта если у клиента не задан next_auto_acount. 0 = выпускать сразу |
BANK_DOC_UPLOAD_GCS | true | Kill-switch GCS-загрузки PDF |
BANK_CREDIT_WARN_AMOUNT | 50000 | Сумма ₽ выше которой credit-модалка показывает warning |
IMAP-приёмник и whitelist
IMAP-настройки подключаются к SmitMailServ на mail.вашдомен.ru:993 (SSL). Ящик bank@billing.вашдомен читает все UNSEEN-письма, сохраняет вложения .csv/.txt в таблицу BankStatementImport. Whitelist отправителей в виде запятой-разделённой строки доменов: @alfabank.ru,@sberbank.ru,@sbrf.ru. Письма от других отправителей игнорируются (статус skipped).
Автонастройка ящика. Кнопка «Автонастроить ящик» создаёт
почтовый ящик приёма выписок (по умолчанию bank@billing.smit34.ru —
на домене почтовой инфраструктуры биллинга, а не на домене ЛК организации),
прописывает DNS-записи и заполняет IMAP автоматически. Если ящик уже задан в
IMAP_BANK_USER, берётся его адрес. Когда ящик настроен, блок
сворачивается в строку «Ящик bank@billing.smit34.ru настроен для приёма
выписок» с кнопкой «Изменить» — поля IMAP скрыты, чтобы не мешать;
«Изменить» раскрывает их обратно.
Telegram-алерты по unmatched
Celery beat bank-statements-unmatched-alert запускается ежечасно. Если есть pending платежи ≥ BANK_TG_ALERT_MIN, отправляет сводку в чат: список последних 10 платежей (сумма, плательщик, банк, дата) + итоговая сумма + кнопка-ссылка на очередь модерации. Anti-spam: при стабильном количестве pending повторный алерт не отправляется (cache bank_unmatched_alert:last_count TTL 24h).
В UI кнопка «Добавить» парсит ссылку https://t.me/c/2910452601/18140 → автоматически заполняет chat_id=-1002910452601 и thread_id=18140. Поддерживаются 3 формата: /c/<chat>/<thread>, https://t.me/<username>, числовой -100....
6.4.2. Банки и парсеры

Регистр банков с привязкой к парсерам и email-доменам отправителей. По умолчанию загружены Сбербанк и АльфаБанк через миграцию 0144 (data-seed). Без активных записей здесь IMAP-приёмник игнорирует все входящие письма.
Колонки таблицы: # | Банк (название + slug) | Email-домен | Парсер (цветной чип) | Импортов (async-счётчик) | Статус (активен/выключен) | Заметки | Действия (редактировать/удалить).
Модалка «Добавить банк»:
- Название банка (например, «Тинькофф Банк»)
- Slug — латинский идентификатор. Автогенерация через транслитерацию ГОСТ 7.79: «Сбербанк» →
sberbank - Email-домен отправителя (валидация: должен начинаться с
@и содержать точку) - Парсер:
sber/alfa/generic(custom mapping для нестандартных CSV) - Toggle «Включён»
- Заметки (textarea)
Добавление нового банка (например, Тинькофф):
- Создать парсер в
billing/services/bank_parsers/<slug>.py— наследовать отBankParser, реализоватьparse(content: bytes) → List[ParsedOperation] - Зарегистрировать в
billing/services/bank_parsers/__init__.py::detect_and_parse()— добавить ветку определения формата - Через UI «Добавить банк» создать
BankParserBindingс новымparser_slug - Whitelist в настройках обновится автоматически (читает из BankParserBinding)
Защита от потери данных: при удалении банк-парсера BankStatementImport с этим email_domain в БД сохраняются (FK не настроен). Новые письма с домена будут игнорироваться. Восстановить — повторное добавление с тем же доменом.
6.4.3. Очередь модерации

Ключевая страница для финансиста-оператора: через неё проходит 50–100 платежей в день. Один платёж разбирается в один клик через массовое действие или в два — через модальное окно.
Возможности
- Chip-фильтры по статусу: На модерации / Сопоставлены / Зачислены / Отклонены / Все — со счётчиками, auto-refresh 30 сек (pulse-анимация при изменении), Page Visibility API (пауза при скрытой вкладке)
- Bulk-actions: чекбоксы + master-checkbox + sticky-toolbar gradient — «Зачислить выбранные» / «Отклонить» (с dropdown типовых причин)
- BS-модалки вместо confirm/prompt/alert:
- Credit — preview через
credit_preview/endpoint: баланс «До → После», risk-флаги (большая сумма / fuzzy / расхождение ФИО) - Adaptive confirm-button: зелёная без рисков, жёлтая warning, красная danger. Auto-focus только если нет danger (защита от случайного Enter)
- Reject — dropdown типовых причин (Не наш / Дубль / Возврат / Ошибка плательщика / Другая) + textarea
- Credit — preview через
- AJAX-update без reload: Toast + зелёная вспышка строки (1.7 сек), scroll и фильтр НЕ теряются
- Undo-banner: 8 сек countdown после Credit/Reject/Bulk — кнопка «Откатить» создаёт storno FinOp + откат баланса + status → manual_review
- Keyboard shortcuts (vim-style): j/k навигация, x чекбокс, c/r/l Credit/Reject/Link, a выбрать всё, g m/c/a/r навигация по фильтрам, ? help-модалка со всеми shortcut'ами
- Sticky-колонки: чекбокс слева, «Действия» справа — на 1366px laptop скроллится середина, ключевые колонки всегда видны
- Иконки в статусах для colour-independence:
fa-hourglass-half/fa-link/fa-check-circle/fa-times-circle - Onboarding-tooltip 4 шага при первом визите (localStorage
bq_onboarding_seen=v4). Shift+Click на help-иконку для перезапуска - Empty-state с CTA: контекстный текст по фильтру + кнопки «Забрать сейчас / Журнал импортов / Показать все»
Credit-модалка (детально)
При клике «Зачислить» fetch'ит /admin/finance/bank_queue/<id>/credit_preview/ и собирает модалку с:
- 2 колонки (Платёж / Клиент) — детальные таблицы
- Balance-flow box «До → После» с цветной типографикой (красный для отрицательных, зелёный для положительных)
- Risk-флаги (warning/danger alerts) — большая сумма ≥
BANK_CREDIT_WARN_AMOUNT, fuzzy-стратегия, расхождение ФИО плательщика и клиента - Adaptive button — цвет и текст меняются по уровню риска
Onboarding-tooltip

При первом визите показывает 4-step tour: Bulk-операции → Keyboard shortcuts → Undo → Risk-проверка. Bump версии (v4 → v5 в JS) — снова покажется после новых фич. Shift+Click на help-иконку (клавиатура в toolbar) — перезапуск.
Путь платежа: от письма банка до баланса клиента
flowchart TD MAIL["Письмо банка
с выпиской"] --> PARSE["Разбор вложения"] PARSE --> ORG["Определение юрлица
по счёту получателя"] ORG --> CHK{"Сводное перечисление
приёмщика платежей?"} CHK -->|"да"| REG["Статус «Сводный реестр»
по клиентам не разносится"] CHK -->|"нет"| MATCH{"Сопоставление
с клиентом"} MATCH -->|"нашли одного"| MTD["Сопоставлена"] MATCH -->|"несколько или никого"| MAN["На модерации
оператор привязывает вручную"] MAN --> MTD MTD --> RISK{"Есть признаки
расхождения?"} RISK -->|"да"| ONE["Разбирается поштучно
в массовое зачисление не попадает"] RISK -->|"нет"| CRED["Зачисление на баланс"] ONE --> CRED CRED --> DOC["Счёт и акт для юрлица
от нужной организации"]
Сводные перечисления приёмщиков платежей

Клиент платит через кассу Сбербанка или терминал «Единой кассы», приёмщик копит оплаты за период и перечисляет провайдеру одной строкой. В назначении так и написано:
ЗА ИНТЕРНЕТ,ТВ,СВЯЗЬ; ПО ПЛАТЕЖАМ С 01/06/2026 ПО 01/06/2026, СУММА 136398.00, КОЛ-ВО 138, ЭЛ.РЕЕСТР EPS…
За такой строкой стоят 138 разных клиентов, и их оплаты уже зачислены другим каналом. Привязать перечисление к одному клиенту нельзя, а разнести повторно — задвоить деньги. Поэтому оно получает статус «Сводный реестр», уходит из очереди ручного разбора и остаётся в журнале как поступление на расчётный счёт.
Такие платежи были самыми крупными в очереди, и оператор упирался в них первыми. После разделения очередь ручного разбора стала посильной:
| Очередь ручного разбора | Платежей | Сумма |
|---|---|---|
| До разделения | 69 | 2 439 244,60 ₽ |
| После | 51 | 136 836,00 ₽ |
| Вынесено в «Реестры» | 18 | 2 302 408,60 ₽ |
Как отличается реестр от обычного платежа
flowchart LR
P["Платёж из выписки"] --> A{"ИНН плательщика
в списке приёмщиков?"}
A -->|"нет"| ORD["Обычный платёж
идёт на сопоставление"]
A -->|"да"| B{"В назначении есть
признак реестра?"}
B -->|"нет"| ORD
B -->|"да"| REG["Сводный реестр"]
Признаков должно быть два сразу. Одного ИНН мало: со счёта того же банка приходят и обычные платежи юрлиц-клиентов — их распознавание пропускает дальше, на сопоставление. Признаки реестра в назначении: «ЭЛ.РЕЕСТР», «ПО ПЛАТЕЖАМ С …», «за приём платежей».
Список ИНН приёмщиков — настройка BANK_AGGREGATOR_INNS в модуле, а не константа в коде: появится третий приёмщик — оператор добавит его сам. По умолчанию там ПАО Сбербанк и РНКО «Единая касса».
Разбор очереди, организации и аудит

Аудит модуля 24.08.2026 показал, что очередь стояла не из-за неудобств интерфейса, а из-за трёх дефектов.
- Ручная привязка платежа была невозможна. Поиск клиента уходил на
/rest_api/v2/Abonents/?search=…, а этот API не знает параметраsearch— возвращались первые клиенты подряд. Плюс в разметке результатов стоялоa.pk, тогда как ключ называетсяid: строки рисовались как#undefined, а клик отправлялabonent_id=undefined. Отсюда платежи, висевшие на модерации с мая. - Баннер отката висел постоянно. Класс
.bq-hiddenобъявлен выше по файлу, чем.bq-undo-banner{display:flex}— при равной специфичности побеждает нижнее правило. Жёлтая плашка «операция выполнена» показывалась на каждой загрузке, а панель массовых операций была развёрнута всегда. - Счётчик импортов на странице парсеров запрашивал JSON у страницы, которая отдаёт HTML — спиннеры крутились вечно.
Привязка платежа: контекст и данные ФНС

Поиск клиента идёт по ФИО или названию, номеру договора, телефону, e-mail, ИНН и номеру клиента. Клиенты с совпавшим ИНН поднимаются в начало списка.
Форма раскрывается прямо под платежом — соседние строки остаются на виду, а именно по ним видно, что тот же плательщик заплатил дважды или что рядом лежит платёж того же юрлица. На телефоне вместо раскрытия выезжает панель. Форма существует в одном экземпляре и переносится между строкой и панелью, поэтому поиск и подсказки работают одинаково.
Видно сам платёж — сумму, дату, банк, плательщика с ИНН и назначение — и кнопки-подсказки с номерами из назначения: клиент часто пишет туда номер договора. Если ИНН плательщика в базе не найден, реквизиты подтягиваются из ФНС через DaData: название, адрес, руководитель и кнопка «Искать по названию из ФНС».
Организация платежа
Импорт и операция запоминают юрлицо-получателя — оно определяется по расчётному счёту из выписки. В очереди и журнале появилась колонка «Орг.», списки скоупятся переключателем организации в шапке и правами сотрудника.
Счёт и акт теперь выписываются от того юрлица, на чей счёт пришли деньги. У каждого юрлица своя серия номеров документов: сквозная нумерация оставляла бы в нумерации одной компании дыры на местах документов другой.
Флаги расхождений в сопоставлении
Три случая помечаются значком и подсветкой строки: совпадение по похожести ФИО, один ИНН у разных клиентов, расхождение ФИО плательщика и клиента. Такие строки не попадают в массовое выделение — их разбирают по одному. При установке галочки «выбрать все» оператор видит, сколько платежей пропущено и почему.
Поиск, период, постраничный вывод и итоги
- Поиск по плательщику, ИНН, лицевому счёту, назначению, имени и договору клиента, номеру операции
- Диапазон дат через общий компонент выбора периода
- 20 / 50 / 100 / 200 строк на странице, постраничная навигация
- Итог по отфильтрованному: сколько платежей и на какую сумму. Крупная сумма показана коротко — «1,2 млн ₽», точное значение — во всплывающей подсказке.
- Фильтр по клиенту
?abonent=<id>— переход из карточки клиента
Панель управления — в одну строку. Поиск, выбор периода и размер страницы сужены так, чтобы вместе с кнопкой «Применить» и инструментами раздела (горячие клавиши, настройка колонок, «Журнал» импортов, «Настройки») уместиться в одну линию. Итог по выборке прижат к правому краю той же строки.
Журнал аудита
Запись создаётся на каждое изменение: сохранение настроек с перечнем правок (включая выключатель автозачисления), ручной забор писем, повторный разбор импорта, автонастройка почтового ящика, массовые действия, ручная привязка с суммой и плательщиком, генерация документов с указанием организации, приём письма и определение организации.
Вкладка «Банк» в карточке клиента

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

На телефоне строка разворачивается карточкой «поле — значение», сумма показана крупно, кнопки во всю ширину. Чекбоксы массового выбора на телефоне скрыты: платежи здесь разбирают по одному.
6.4.4. Журнал импортов

Полный лог писем от банков с возможностью отладки. По умолчанию показывает последние 30 дней (защита от бесконечной выдачи при N тысячах импортов).
Фильтры в одну строку: Банк (Альфа/Сбер/Неизвестно/Все) | Статус (Новые/Разобранные/Ошибки/Без вложений) | Период (7д/30д/90д/Все) | кастомный date-range. Meta-bar над таблицей показывает текущий период + количество найденных записей.
Колонки: # | Получено (datetime) | От (email) | Тема | Банк (chip) | Файл (filename) | Статус (с иконкой) | Операций (всего / сматч. / зачисл.) | Действия.
Действия:
- «Операции» (
fa-eye) → переход в очередь модерации с фильтром?import_id=<pk>(отображает только операции этого письма) - «Перепарсить» (
fa-redo-alt) — для status=error: сбрасываетparser_error+ ставитstatus=new+ запускаетprocess_pending_imports.apply() - Для status=parsed — кнопка
fa-sync-altдля повторного парсинга (создаст дубликаты только если UNIQUE(bank, external_id) не сработает)
Статусы письма-импорта
Колонка «Статус» в журнале — это статус письма с выпиской (модель BankStatementImport, набор IMPORT_STATUS_CHOICES). Всего 5 значений:
| Статус (UI) | Код | Когда выставляется |
|---|---|---|
| 🟡 Новый | new | Дефолт. Письмо получено по IMAP, вложение сохранено, но ещё не разобрано парсером |
| 🟢 Разобран | parsed | Парсер успешно прочёл вложение и создал записи BankStatementOperation |
| 🔴 Ошибка парсинга | error | Парсер упал на файле — текст ошибки сохраняется в поле parser_error, виден при наведении |
| ⚪ Без вложений | empty | В письме нет файла выписки (.csv/.txt) |
| ⚪ Пропущен | skipped | Письмо не от банка — домен отправителя не входит в whitelist «Банки и парсеры» |
Как меняется статус: «Новый» → «Разобран»
Переход выполняет фоновая задача Celery, оператор в нём не участвует. Цепочка:
bank-statements-pull(Celery beat, ежечасно) — приёмникbilling/services/imap_client.pyчитает UNSEEN-письма из ящикаbank@вашдомен.ruи создаётBankStatementImportсо статусомnew.bank-statements-process(Celery beat, каждые 5 минут) — функцияprocess_pending_imports()вbilling/tasks/bank_statements.py:- берёт
BankStatementImport.objects.filter(status='new')[:20]; - вызывает парсер по
parser_slugбанка (sber/alfa/generic); - на каждую строку выписки создаёт
BankStatementOperation+ запускает matching; - при успехе —
imp.status = 'parsed'; при сбое парсера —status = 'error'+ текст вparser_error.
- берёт
То есть письмо в статусе Новый автоматически становится Разобран в течение ~5 минут после получения — на следующем тике bank-statements-process. Если статус не меняется дольше — см. блок «Диагностика» ниже.
parsed) означает только, что вложение прочитано и операции созданы. Сами деньги имеют отдельный статус — это набор OPERATION_STATUS_CHOICES модели BankStatementOperation, видимый в /admin/finance/bank_queue/:
Новая (не сопоставлена) → Сопоставлена / На модерации → Зачислена / Отклонена / Дубликат.
Зачисление контролируется kill-switch BANK_AUTO_CREDIT_ENABLED (по умолчанию ВЫКЛ — операции ждут ручного подтверждения оператором).
Диагностика: статус долго не меняется
Если письма зависают в статусе Новый и не переходят в Разобран — задача bank-statements-process не выполняется. Что проверить:
- Жив ли планировщик — контейнер
celery-beatдолжен быть в статусеrunning(docker ps). - Видит ли beat банковские задачи — после деплоя новых beat-задач контейнер
celery-beatобязательно пересоздаётся. Если он запущен на устаревшем образе, задачи изCELERY_BEAT_SCHEDULEв его расписание не попадают, иbank-statements-processмолча не запускается (контейнер при этом «running», ошибок нет). - Ручной запуск как обходной путь — задачу можно выполнить немедленно:
process_pending_imports()разберёт все письма со статусомnew. - Кнопка «Перепарсить» в журнале — для писем со статусом
errorсбрасывает ошибку, ставитnewи сразу запускает разбор.
Шрифтовая пара для PDF
В Брендинге → карточка «Документы» → селект «Шрифтовая пара для PDF». 5 кириллических вариантов:
pt_serif— PT Serif + PT Sans (классика, ParaType, default)roboto— Roboto Slab + Roboto (современный, Google)inter— Inter (UI-friendly, наиболее читаемый)merriweather— Merriweather + Open Sans (газетный)golos— Golos Text (российский, Geometric grotesque)
⚠ Ограничение WeasyPrint: в Docker-контейнере нет доступа к fonts.googleapis.com, поэтому в PDF — fallback на DejaVu Sans. Шрифты применятся только при печати через браузер либо при переходе на Playwright/Chrome headless для PDF-генерации. Поле font_pair сохраняется корректно.
Per-abonent настройки документов
Учитываются существующие поля клиента (вкладка «Настройки» в карточке):
send_act«Отправлять счёт» — выпускать счёт-фактуруauto_account«Формировать акт автоматически» — выпускать актnext_auto_acount«Дата выставления акта» — откладывает акт до даты
Если у юр.лица оба флага OFF — документы не генерируются даже при BANK_AUTO_GENERATE_DOCS=true. Если next_auto_acount не задан, используется fallback на BANK_DOC_DEFAULT_SEND_DAY (день месяца).
Единое оформление всех четырёх страниц
Все четыре страницы раздела — Настройки, Банки и парсеры, Очередь модерации и Журнал импортов — работают на одних и тех же элементах интерфейса: таблицы, фильтры, подтверждения и уведомления ведут себя одинаково.
- Единые табличные компоненты. И очередь, и журнал импортов построены на
SmitTable: порядок, ширина и видимость колонок настраиваются кнопкой «Колонки» и сохраняются в профиле сотрудника, а не в браузере; на телефоне строки автоматически становятся карточками с подписями полей. Полоса статусов —SmitChipBar, панель массовых действий —SmitBulkBar(появляется только при выборе), выбор периода —SmitDateRange, бейдж организации —OrgBadge, всплывающие уведомления —SmitToast, пустые состояния —smit-empty. - Подтверждения. Каждый опасный шаг — включая «Забрать сейчас» — спрашивает подтверждение и перечисляет последствия. Диалог корректен в тёмной теме, на телефоне открывается панелью снизу.
- Тёмная тема — контраст. Приглушённые подписи (итоги, пейджер, мета-строки) в очереди, настройках и журнале читаются с контрастом не ниже WCAG AA.
- Превью документов — только в облаке. Превью PDF счёта/акта загружается в GCS и отдаётся редиректом на подписанный URL (правило проекта «файлы только в GCS»); локальная отдача из
/var/dbосталась fallback'ом при выключенной (BANK_DOC_UPLOAD_GCS=false) или недоступной GCS-загрузке. - Защита от каскадного пробития чеков. «Забрать сейчас» при одновременно включённых автозачислении (
BANK_AUTO_CREDIT_ENABLED) и боевом режиме (FISCAL_ENABLED) требует явного подтверждения: забор писем каскадом зачисляет платежи и пробивает фискальные чеки в ОФД — это необратимо. Осознанное подтверждение отдельно фиксируется в журнале аудита. - Мобильная адаптация. На телефоне списки очереди, журнала и парсеров превращаются в карточки (данные не прячутся за горизонтальным скроллом). Кнопки и карточки статистики на странице настроек раскрываются на всю ширину, длинные подписи сокращены («Очередь», «Журнал», «Забрать»). Кнопки действий в карточках — не меньше 44×44 px (удобно попасть пальцем).
- Единые мобильные фильтры. В очереди и журнале фильтры на телефоне сворачиваются в единый компонент SmitMobileFilters — кнопку «Фильтры» со счётчиком активных фильтров, открывающую нижнюю панель (bottom-sheet). «Колонки» и справка на телефоне скрываются, а «Журнал»/«Настройки»/«Применить» остаются на виду. На странице парсеров кнопка добавления — компактный «+».
- Сквозной переход до чека ОФД. У зачисленной операции в очереди рядом со ссылкой «FinOp #N» появилась прямая ссылка на кассовый чек в ОФД (54-ФЗ) и индикатор статуса пробития (ожидает / ошибка). Цепочка навигации замкнута: письмо-импорт ↔ очередь → финансовая операция → чек ОФД (карточка финоперации, в свою очередь, показывает чек и обратную ссылку на банковскую операцию).
- Привязка платежа — раскрытием строки (по образцу Xero). На широком экране кнопка «Привязать» не открывает модальное окно, а раскрывает строку-аккордеон прямо под операцией: там карточка платежа (сумма, дата, плательщик, ИНН, назначение), поле поиска клиента (ФИО / договор / телефон / e-mail / ИНН / ID) с подсказками-кнопками из назначения платежа и подтверждением перед зачислением. На телефоне (< 768 px) — то же в виде модалки / слайд-панели.




6.4.5. Почтовый сервер (SmitMailServ)
URL: /admin/settings/mailserver/ — управление собственным почтовым сервером SmitMailServ, развёрнутым на хосте mail.вашдомен.ru. Операции с ящиками и доменами доступны из биллинга через API https://mail.вашдомен.ru/api/v1/.

Где заводить ящики, зачем домену организация, что делает роль ящика и куда смотреть, когда «почта не работает».
Вкладка «Обзор»
Состояние сервера, настройки API, защищённые ящики, DKIM/SPF/DMARC.
- Состояние сервера — Статус (Online/Offline) · Версия SmitMailServ · Ящиков (всего/лимит) · Использовано места. Кнопка «Проверить подключение» делает test-request к API.
- Настройки API — Endpoint API, API-ключ (rw) с переключателем видимости, Основной домен (
<select>, подгружается черезGET /admin/settings/mailserver/api/domains/), toggle «Проверять SSL-сертификат». - Защищённые ящики —
bank@вашдомен.ru,noreply@вашдомен.ru,ask@вашдомен.ruи др. Нельзя удалить через UI (server-side защита вget_protected_mailboxes()), чтобы не сломать банковские выписки/рассылку. - DKIM / SPF / DMARC — статус DNS-записей по нажатию «Обновить».

Вкладка «Ящики»
Список всех ящиков сервера: кто владелец, сколько занято, что ящик обслуживает. Строки подгружаются AJAX-ом, поиск идёт по адресу и имени.

Одна строка тулбара: домен, тип ящика, поиск, колонки, добавление. Ниже — таблица с организацией, счётчиком писем и ролями.
Что показывает таблица
| Колонка | Что в ней |
|---|---|
| Активность | Точка: зелёная — ящик принимает и отправляет письма, серая — выключен. Колонка без подписи, самая узкая, скрыть её нельзя. |
| Орг. | Организация домена — тот же бейдж, что в остальных списках биллинга (мультиорг). |
| Адрес. У системных ящиков — щит: их нельзя удалить, на них держатся выписки, рассылка и приём обращений. Скрыть колонку нельзя. | |
| Имя | Отображаемое имя — оно же уходит в подпись и в адресную книгу почты. |
| Квота | Занято из выделенного. По умолчанию колонка скрыта, значение видно в подсказке к счётчику писем. |
| Писем | Непрочитанных из всех. Клик открывает ящик в почте без ввода пароля. |
| Создан | Дата создания, полностью, без сокращения. |
| Чей | Сотрудник-владелец с аватаркой. У системного ящика владельца нет — прочерк. |
| Роли | Что ящик обслуживает: приём обращений, голосовая почта, рассылки, банковские выписки. Нажатие переключает роль. |
| Ред. | Меню строки: войти в ящик, редактировать, сменить пароль, включить или выключить, удалить. |
Роли ящика
Роль — это ответ на вопрос «что этот ящик делает для биллинга». Назначенная роль показана подписью, остальные остаются значком с подсказкой: в списке на сотню строк важно видеть включённое, а не перечень возможного.
flowchart LR BOX["Ящик
ask@вашдомен.ru"] BOX -->|Поддержка| TICKETS["Обращения
письмо → тикет"] BOX -->|Голосовая| VOICE["Голосовая почта
запись → заявка"] BOX -->|Рассылка| SEND["Уведомления и рассылки
отправитель писем"] BOX -->|Выписки| BANK["Банковские выписки
разбор вложений"] classDef on fill:#e8f7ef,stroke:#43b77a,color:#1b5e3f classDef box fill:#f4f6f8,stroke:#adb5bd,color:#212529 class BOX box class TICKETS,VOICE,SEND,BANK on
На телефоне
Сверху остаётся то, за чем в раздел заходят: выбор домена и «Добавить». Ниже — поиск, «Фильтры» и обновление в одну строку; фильтр по типу ящика открывается шторкой снизу. Таблица превращается в карточки — по строке на ящик, без горизонтальной прокрутки.
flowchart TB
subgraph D["Десктоп"]
T["Одна строка тулбара:
домен · тип ящика · поиск · колонки · добавить"]
TB["Таблица:
настраиваемые колонки, роли в строке"]
T --> TB
end
subgraph M["Телефон"]
P["Домен + Добавить"]
S["Поиск + Фильтры + Обновить"]
SH["Шторка: тип ящика"]
C["Карточки ящиков"]
P --> S --> C
S -.-> SH
end
D -.->|те же элементы, другая раскладка| M
Добавление ящика (кнопка «Добавить ящик»):

- Домен —
<select>с подгрузкой реального списка из SmitMailServ: опечататься нельзя. - Логин (до @) — локальная часть адреса.
- Пароль + Подтверждение — обязательны. Генератор пароля рядом (фиолетовая иконка
fa-magic). - Квота (МБ) — default 1024. Активен — toggle.
- При создании системных ящиков (bank@/noreply@/ask@…) пароль автоматически синхронизируется в SystemSettings (
_sync_password_to_settings()), чтобы IMAP-парсер банковских выписок и SMTP-рассылка биллинга получили актуальный пароль одним нажатием.
Вкладка «Админы доменов»

Управление доменными админами SmitMailServ. У админа можно назначить набор доменов, которыми он управляет (<select multiple> с тем же AJAX-источником). Полезно если на сервере несколько обслуживаемых доменов — каждому даём отдельного админа.
REST API внутри биллинга
| Endpoint | Назначение |
|---|---|
GET /admin/settings/mailserver/api/status/ | Состояние API (status/version/quota/mailbox-counts) |
GET /admin/settings/mailserver/api/test-connection/ | Проверка соединения (с возвратом версии) |
GET /admin/settings/mailserver/api/dkim/ | DKIM/SPF/DMARC статусы по доменам |
GET /admin/settings/mailserver/api/domains/ | Список доменов с метаданными (mailboxes, max_mailboxes, aliases, active, is_default) — питает все <select> доменов |
GET /admin/settings/mailserver/api/mailbox/?domain=… | Список ящиков домена |
POST /admin/settings/mailserver/api/mailbox/create/ | Создание ящика |
POST /admin/settings/mailserver/api/mailbox/<email>/edit/ | Редактирование (имя/квота/active) |
POST /admin/settings/mailserver/api/mailbox/<email>/password/ | Смена пароля (с авто-sync в SystemSettings для системных) |
DELETE /admin/settings/mailserver/api/mailbox/<email>/ | Удаление (server-side защита системных) |
GET/POST/DELETE …/api/domain-admin/… | CRUD доменных админов |
Все endpoint'ы за @user_passes_test(_is_superadmin) — только суперадмин. Каждая CRUD-операция пишет в AuditOperations с table_name='MAILSERVER'.
Как это работает: биллинг обращается к почтовому серверу по API — адрес сервера и ключ доступа задаются в этом же разделе настроек. Запросы повторяются при сетевых сбоях, ошибки API видны в журнале.
Веб-почта: календарь, контакты, брендинг
Сотрудники работают с почтой в браузере по адресу https://mail.<домен>/
(например mail.вашдомен.ru).
Кроме писем там есть календарь, задачи и адресная книга. Интерфейс подхватывает данные из
биллинга: имя сотрудника, его фото, подпись, контакты коллег и фирменные цвета организации,
которой принадлежит домен.
Войти можно двумя способами: обычным логином и паролем от биллинга либо из админки — раздел «Почтовый сервер» → вкладка «Ящики» → меню строки → «Войти в ящик» (вход без ввода пароля, каждый такой вход пишется в аудит; возможность отключается настройкой, см. «Настройки сервера»).
flowchart LR
U["Сотрудник
браузер"] --> HN["nginx хоста
mail.домен"]
HN --> MN["nginx почты
статика + брендинг"]
MN --> SG["SOGo
веб-интерфейс"]
SG --> DV["Dovecot
письма IMAP"]
SG --> PF["Postfix
отправка SMTP"]
SG --> PG[("Настройки SOGo
база sogo")]
SG --> BV[("Биллинг
ящики и контакты")]
MN -. "цвета, логотип" .-> API["API брендинга
биллинга"]
API --> ORG[("Карточка
организации")]
Брендинг по организации
Почта каждой организации выглядит по-своему: цвет интерфейса и логотип берутся из карточки организации, к которой привязан почтовый домен (раздел «Организации» → «Брендинг»). Ничего настраивать отдельно для почты не нужно — поменяли фирменный цвет в карточке, он появился и в почте.
Что окрашивается: верхняя панель и шапка списка, кнопка создания, ссылки, выделение выбранной папки, а в календаре — сегодняшний день, колонка текущего дня и события личного календаря. Логотип организации встаёт в левый край верхней панели.
sequenceDiagram
participant B as Браузер
participant N as nginx почты
participant A as API биллинга
participant O as Карточка организации
B->>N: открыть почту
N-->>B: страница SOGo + скрипт брендинга
B->>A: какой брендинг у почтового домена
A->>O: домен → организация
O-->>A: цвет, логотип, название
A-->>B: настройки брендинга
B->>B: перекрасить интерфейс, вставить логотип
Справка внутри почты
В правом верхнем углу, слева от кнопки выхода, есть значок «?» — он открывает этот раздел документации.

Кнопка справки соседствует с выходом — там, где её ищут.
Имя, подпись и фото из профиля
Ящик сотрудника берёт данные из его профиля в биллинге: не нужно отдельно заполнять имя отправителя и вручную набирать подпись.
- Имя отправителя — ФИО из профиля. У ящиков со своим названием («Банковские выписки», «Поддержка СмИТ») название сохраняется: такие письма должны уходить от службы, а не от закреплённого за ящиком человека.
- Подпись — собирается автоматически: ФИО, роль, телефон, адрес ящика, сайт и реквизиты организации домена, плюс фото сотрудника.
- Фото — то же, что в профиле; видно и в интерфейсе почты, и в подписи у получателя письма.
Данные обновляются сами: при сохранении профиля, смене фото, создании ящика и смене
владельца. Разовый прогон по всем ящикам — команда
manage.py sync_mail_identities (ключ --dry-run покажет, что получится,
без записи).
flowchart TD
P["Профиль сотрудника
ФИО, телефон, фото"] --> S{"Синхронизация"}
O["Организация домена
название, сайт, телефон"] --> S
S --> N["Имя отправителя"]
S --> G["Подпись письма"]
S --> F["Фото в интерфейсе
и в подписи"]
S --> C["Личная книга и календарь
названы по организации"]

Блок «Почта» в профиле: ящики сотрудника, переключатели уведомлений, адрес пересылки и подсказка про пароль.
Адресная книга из биллинга
В почте есть общая книга «Контакты». Она только читается — данные ведутся в биллинге:
- Сотрудники — ФИО, рабочий адрес и телефон из профиля. Показываются всегда.
- Клиенты — имя, адрес и договор. По умолчанию скрыты: это персональные данные, а книга видна всем владельцам ящиков. Включается переключателем в «Настройках сервера».
Поиск работает и по имени, и по адресу — достаточно начать набирать фамилию в поле получателя, и адрес подставится сам. Личная книга и календарь названы по организации домена (например «Контакты СмИТ Поддержка») вместо стандартного «Personal Address Book».

Общая книга «Контакты» рядом с личной книгой сотрудника.
Вкладка «Почта» в панели уведомлений
Чтобы прочитать письмо, не обязательно открывать веб-почту: в панели уведомлений биллинга (колокольчик в правом верхнем углу) есть вкладка «Почта». Там лента писем из всех ящиков сотрудника — с отправителем, адресом, папкой и временем («15 минут назад», «вчера»). Избранные письма закреплены сверху.
Письмо открывается в правой колонке. Оттуда же можно:
- ответить — поле с форматированием и вложениями, как в переписке чата;
- переслать письмо другому адресату;
- отметить избранным или непрочитанным, убрать в спам или корзину;
- скачать вложение и открыть письмо в самой почте.
Ответ уходит от ящика сотрудника, поэтому получатель отвечает ему, а не на общий адрес; ящик-отправитель выбирается списком, если ящиков несколько. Какие ящики показывать в ленте, каждый выбирает у себя в профиле; вкладку целиком можно выключить в «Настройках сервера».

Лента писем и открытое письмо с полем ответа.
Настройки сервера
Раздел «Почтовый сервер» → вкладка «Настройки сервера». Кроме технических параметров (имя сервера, размер письма, лимит отправки, relay, DKIM) там есть переключатели, которые влияют на повседневную работу:
| Настройка | Что делает |
|---|---|
| Сбор почтовых метрик, мин | Как часто пересчитывать занятое место и число писем для колонок «Квота» и «Писем». Обход идёт по файлам ящиков, поэтому чаще, чем раз в 10–15 минут, смысла нет; 0 — не собирать. |
| Разрешить персоналу создавать email | В профиле сотрудника появляется блок создания ящика в доступных ему доменах. |
| Показывать вкладку «Почта» в уведомлениях | Общий выключатель ленты писем в панели уведомлений. |
| Брать имя и подпись из профиля | Ящик подписывается ФИО владельца, в письма подставляется подпись с должностью, телефоном, фото и реквизитами организации. |
| Показывать клиентов в адресной книге | Добавляет клиентов в книгу «Контакты». Это персональные данные — по умолчанию выключено. |
| Разрешить вход в ящик без ввода пароля | Кнопка «Войти в ящик» открывает чужую почту от имени владельца. Каждый вход пишется в аудит; если такой доступ не нужен — выключите. |
Здоровье сервера и доставляемость
Вкладка «Сервер» отвечает на два вопроса: работает ли почта прямо сейчас и дойдут ли письма до получателя, а не в спам.
Здоровье сервера — по строке на каждую часть почты. Все строки зелёные — почта принимается и отправляется. Очередь показывает, сколько писем ждёт отправки; норма — ноль. Кнопка с круговой стрелкой перезапускает одну упавшую часть, не трогая остальные.
flowchart LR NET["Интернет"] -->|SMTP| PF["Приём и отправка
postfix"] PF --> RS["Антиспам
rspamd"] RS --> DC["Хранение и чтение
dovecot"] DC --> SG["Веб-почта
sogo"] SG --> NG["Веб-почта, сайт
sogo-nginx"] NG -->|браузер| USER["Сотрудник"] RD["Кэш
redis"] --- RS RD --- SG BIL["Биллинг"] -->|IMAP: обращения, выписки| DC BIL -->|SMTP: уведомления| PF
Письма доходят, а не в спам — четыре проверки на каждый домен: подпись писем, разрешение на отправку, защита от подделки и запись приёма почты. Все зелёные означают, что письма с этого домена принимают Gmail, Mail.ru и Яндекс; красная — письма могут уходить в спам, и настраивать её нужно в разделе «Домены и DNS».
Колонка «Писем» в списке ящиков
В списке ящиков рядом с квотой показывается «непрочитанных / всего». Клик по счётчику открывает ящик в почте. Пока сбор не отработал, вместо чисел стоит прочерк — это не то же самое, что «писем нет».

Список ящиков: роли, владелец, занятое место и счётчик писем.
6.4.5А. Домены и DNS (Cloudflare)
URL: /admin/settings/dns/ — управление DNS-зонами через Cloudflare API прямо из биллинга: зоны и записи (CRUD), сценарии в один клик и диагностика.
- Доступ — Global API Key или Scoped Token; ключи задаются глобально либо для каждой организации отдельно (мультиорг: у каждой компании свой аккаунт Cloudflare).
- 1-клик «Почта» — создаёт полный набор записей домена:
A(mail.домен),MX,SPF,DKIM,DMARC. - 1-клик «Поддомен» — добавляет
A/CNAMEна сервер (напримерlk.домен). - Диагностика — проверка почтовых записей домена и резолва хоста.
6.4.6. Автонастройка почтовых ящиков и DNS
Единый сервис провижинга (billing/services/mailbox_provisioning.py) создаёт почтовый ящик, прописывает DNS-записи и заполняет настройки подключения — одной кнопкой. Работает везде, где системе нужен ящик.
Что делает автонастройка
- Регистрирует домен в почтовом сервере (идемпотентно — повторный запуск безопасен).
- Создаёт ящик
<имя>@<домен>с сгенерированным паролем. Если ящик уже существует — переиспользует его пароль, ничего не сбрасывая. - Прописывает DNS-записи почты в Cloudflare:
A(mail.домен),MX,SPF,DKIM,DMARC. - Заполняет параметры подключения (SMTP и/или IMAP) в том модуле, откуда запущена.
Где доступна
| Раздел | Что настраивает | Проверка |
|---|---|---|
| Организации → вкладка «Почта (SMTP)» | ящик noreply@ + SMTP организации |
«Проверить» (коннект + авторизация), «Отправить тест-письмо» (HTML на ваш e-mail) |
| Поддержка → карточка ящика → вкладка «Почта» | ящик приёма обращений + IMAP и SMTP | «Проверить IMAP», «Отправить тест» |
| Банковские выписки | ящик bank@ + IMAP приёма выписок |
«Проверить» IMAP-подключение |
| Профиль сотрудника | личный ящик сотрудника | вход в веб-почту одной кнопкой |
| Домены и DNS | поддомен (A/CNAME) | проверка DNS-резолва хоста |
Ящик сотрудника и пересылка
В профиле (/admin/settings/profile/) сотрудник создаёт себе ящик, если включена настройка «Разрешить персоналу создавать email». Логин подставляется из имени пользователя, пароль генерируется автоматически — достаточно нажать «Создать». Опционально указывается адрес пересылки: копии входящих уходят на внешний адрес, оригинал остаётся в ящике.
admin, info, postmaster и другие зарезервированные логины; лимит — один ящик на домен.