Граф Wiki

Настройки: система и платежи

Общие настройки, печатные формы, фискализация, платёжные системы, банковские выписки и почтовый сервер.

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

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, reCAPTCHA, блокировка, сессия

БлокЧто делает
Авторизация через FIDO2/WebAuthn
SECURITY_WEBAUTHN_ENABLED
Вход по passkey (YubiKey, Touch ID/Face ID, Windows Hello). После включения сотрудники привязывают ключ в Профиле (любой сотрудник, не только su; модель StaffWebAuthnCredential), клиенты — в ЛК. На странице входа в биллинг появляется кнопка «Войти по ключу (passkey)».
Google reCAPTCHA v3
RECAPTCHA_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), освобождая место без потери пунктов.

Адаптивная шапка в сжатом виде

Вкладка «Аудит» — настройки журнала действий по клиентам

Управление параметрами вкладки Аудит в карточке клиента и общим поведением логирования. Доступна по адресу /admin/settings/system/?tab=audit только пользователям группы root или с is_superuser=True.

Настройки аудита — форма с 4 параметрами

ПараметрДиапазон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.

Toolbar вкладки Аудит клиента с шестерёнкой настроек

Вкладка «Логи» — хранение и уровень логирования

Управление файлами журналов в /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 на хосте.
Уровень логирования Django
LOG_LEVEL
DEBUG / INFO / WARNING / ERROR INFO Влияет на error.log и celery_*.log. Применяется после перезапуска контейнеров.
Verbosity FreeRADIUS
FREERADIUS_DEBUG_LEVEL
info / debug / trace info info — только Accept/Reject (~10 MB/сутки). debug (флаг -X) — детально (~100 MB/сутки). trace (флаг -xx) — полная трассировка (~800 MB/сутки, не использовать в проде).
Сжимать ротированные файлы gzip
LOG_COMPRESS
bool true Архивы прошлых дней сжимаются (≈ ×10 экономия места). Чтение через zcat имя.gz.

Справа на вкладке — таблица текущего размера всех файлов в /var/log/django/ с подсветкой больших (≥100 МБ оранжевый, ≥1 ГБ красный). Клик по имени файла → переход в просмотр содержимого (/admin/reports/dev/logs/).

Просмотр логов с подсветкой

Страница /admin/reports/dev/logs/ (раздел «Отчёты → Разработка и логи», только root-доступ) показывает 12 каналов журналов слева с текущим размером, справа — содержимое выбранного файла.

Просмотр логов с подсветкой по уровням

Ротация логов на сервере

Часть логов пишет 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.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 + смена пароля).

Вкладка Безопасность: финансовые операции + доступ суперпользователя + Web-консоль

Вкладка «Блокировки и финансы» — 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):

Запрос к Telegram / Нейросети 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 / Только Нейросеть / Обе), Удалить.

Таблица прокси с открытым kebab-меню действий

«Проверить все» — проверяет все прокси и расставляет приоритеты: живые по возрастанию задержки (быстрый = приоритет 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().

Шаблоны документов — договоры, акты, квитанции. Шаблон — это HTML или Word-файл с подстановочными переменными вида {{ contract_number }}, {{ abonent.name }}, {{ tariff }}. Готовый документ генерируется при печати из карточки клиента.

Шаблоны печати

6.3. Фискализация (54-ФЗ)

Автоматическая отправка кассовых чеков в ОФД: модуль фискализации, какие платежи фискализируем, чек-лист готовности и очередь чеков.

6.3.1. Модуль фискализации 54-ФЗ

Модуль формирует кассовый чек и передаёт его в ОФД при приёме оплаты — согласно Федеральному закону № 54-ФЗ. Чек бьётся собственной кассой организации, реквизиты продавца (ИНН, СНО, ставка НДС) берутся из брендинга компании — единый источник, без дублирования в карточке кассы.

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

Зачем нужен модуль, какие платежи фискализируем и почему агрегаторы мимо, чек-лист готовности к боевому режиму, карточка кассы и очередь чеков. С озвучкой.

Чек бьём только по своему безналу

Платёжные агрегаторы — Ю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}, {абонент}
Готовность к боевому режиму

Главный выключатель FISCAL_ENABLED по умолчанию выключен: чеки в ОФД не уходят. Включить его напрямую нельзя — тумблер ведёт в чек-лист, и пока обязательные пункты не выполнены, кнопка «Включить боевой режим» заблокирована. Сервер проверяет то же самое: запрос на включение мимо интерфейса будет отклонён.

Чек-лист готовности к боевому режиму

ПунктБлокирует включениеЧто означает
Касса с поддерживаемым типомдатип «Другая» драйвера не имеет
Логин, пароль и группа ККТдабез них ОФД не примет ни одного чека
Связь с ОФД проверенадарезультат проверки живёт 5 минут
Задан ИНН продавцадаберётся из реквизитов компании
ИНН кассы совпадает с ИНН компаниинетв чек уйдёт ИНН компании; расхождение обычно означает опечатку
Выбраны источники и типы операцийнетпусто = разумный набор по умолчанию
Очередь чеков

Раздел Отчёты → Очередь чеков (/admin/reports/fiscal_queue/) показывает, что именно ждёт отправки. Раньше состояние очереди было видно только строкой счётчиков в настройках, без возможности посмотреть содержимое.

Список построен на единых компонентах: строки подгружаются по мере прокрутки (бесконечная загрузка), действия строки собраны в компактное меню, клик по имени клиента открывает боковую карточку клиента, а на телефоне строки превращаются в карточки с подписями полей. Период задаётся единым выбором дат с пресетами. Клик по имени клиента открывает боковую карточку абонента и сразу прокручивает к блоку «Банк» с его платежами из выписок.

Очередь чеков: состояния, фильтры, список операций с источником и статусом

Очередь чеков в тёмной теме

Как работает (поток чека)
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-алерт"]
  1. Приём оплаты — зачисление банковской выписки создаёт финоперацию.
  2. Движок проверяет источник, сумму и тип операции, собирает состав чека по 54-ФЗ и ставит задачу в очередь.
  3. Очередь отправляет чек в ОФД, опрашивает статус, повторяет при сбоях и шлёт Telegram-алерт на застрявшие чеки.
  4. Чек клиенту — электронный чек на e-mail или телефон, ссылка в личном кабинете и в мобильном приложении, фискальные реквизиты в карточке операции.
Статусы чека

Старые операции автоматика не досылает

Досылаются только свежие — не старше порога FISCAL_PENDING_MAX_AGE_DAYS (по умолчанию 3 дня). По 54-ФЗ чек пробивается в момент расчёта; пробить пачку чеков задним числом — решение бухгалтерии, а не побочный эффект включения тумблера. Такие операции остаются в очереди и отправляются вручную.

Касса (доступ к ОФД)

Параметры доступа вводятся в карточке кассы: тип кассы, URL сервера ОФД, группа ККТ, логин и пароль, организация, ИНН, место расчётов, система налогообложения, e-mail продавца и флаг тестового сервера.

Карточка кассы: доступ к ОФД, организация, налогообложение

В списке касс колонка «Состояние» показывает, чего кассе не хватает («нет: логин, пароль, группа ККТ») или что ИНН расходится с компанией — без открытия карточки.

Боевой режим: общий и по кассе

Чек уходит в ОФД, только когда включён и общий рубильник (FISCAL_ENABLED), и боевой режим кассы организации платежа. Касса без явного флага наследует общий — так одна касса работает как раньше, а у нескольких организаций режим и источники независимы.

flowchart TD
  S{"Общий рубильник
FISCAL_ENABLED"} -->|"выключен"| N["Чек не уходит"] S -->|"включён"| K{"Режим кассы
организации"} K -->|"наследует общий"| Y["Чек уходит в ОФД"] K -->|"включён"| Y K -->|"выключен"| N
Права и журнал
Чек в карточке операции

На странице Финансовые операции в карточке есть секция «Чек» со статусом ОФД, номером ФД/ФП и ссылкой на электронный чек. Клиент видит ссылку на чек в личном кабинете и в мобильном приложении.

Налогообложение

При работе на УСН без НДС в чек передаётся признак «НДС не облагается». Ставка НДС и система налогообложения берутся из реквизитов компании (Брендинг); при переходе на ОСН переключатель ставки уже готов.

6.4. Платёжные системы

Настройка приёма онлайн-платежей: через что клиент платит из личного кабинета и мобильного приложения, какая берётся комиссия и с каких адресов принимается webhook.

Обучающее видео 3:03

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

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

Платёжные системы — общие настройки

Наборы настроек: общие и кассы организаций

Страница правит два разных набора, между ними переключает полоса в шапке:

Касса организации

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

Что остаётся общим для всех организаций

Активная платёжная система, комиссия, валюта W1, секрет подписи Generic/UCS и белый список IP. На уровне организации переопределяются только реквизиты кассы, адреса возврата клиента и расчётный счёт приёма оплат.

Секретные ключи

Секреты в браузер не отдаются: в поле показывается только маска с опознавательным хвостом (••••••••2bc9). Пустое поле при сохранении означает «не менять» — чтобы заменить ключ, введите новый.

Маска секретного ключа

Проверка подключения

Кнопка «Проверить подключение» различает три исхода, а не два:

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

Честный статус проверки подключения

Проверку можно выполнить для любой системы, в том числе неактивной — переключать боевой приём платежей для этого не нужно. Неактивная система помечается пунктирной рамкой и бейджем «не активна», её поля остаются читаемыми и доступными для правки.

Провайдеры

Комиссия

Задаётся в процентах (например, 4,5), максимум 20 %; значение проверяется на сервере. Комиссия добавляется клиенту сверху: при пополнении на 500 ₽ и ставке 4,5 % платёжная система спишет 522,50 ₽, а на счёт зачислится ровно 500 ₽. Карточка справа пересчитывает пример при вводе.

Безопасность webhook

Безопасность webhook

Аудит и сохранение

Каждое изменение пишется в журнал аудита (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_systemSystemSettings ключFinTypes по умолчанию
YooKassaLK_PAYMENT_OPTYPE_YOOKASSA«ЮKassa» (приход +1)
W1LK_PAYMENT_OPTYPE_W1«Wallet One (W1)» (приход +1)
cardLK_PAYMENT_OPTYPE_CARDtype_id=40 «Платёж с карты»
generic / fallbackLK_PAYMENT_OPTYPE_GENERICtype_id=23 «Оплата через платежные системы»

Зачем это нужно: у каждой платёжной системы свой FinTypes, и бухгалтерия разделяет источники — отчёты «итого через ЮKassa за месяц» работают через простой фильтр по op_type_id без парсинга поля descr.

Как изменить:

  1. Создать новый тип в Справочники → Типы фин. операций (например, «СБП» или «T-Bank»).
  2. Установить SystemSettings.value для соответствующего ключа = type_id нового типа. Через /admin/settings/system/ или management-команду set_system_setting LK_PAYMENT_OPTYPE_YOOKASSA 51.
  3. Webhook автоматически подхватит новое значение при следующем платеже (без рестарта).

Старые операции (под type_id=23) не переразмечаются — они остаются в истории под прежним типом. Только платежи, начисленные после миграции 0115, получают новые типы. Это безопасно: отчёты с интервалом «после 2026-05-08» получат правильную разбивку, ранние периоды останутся как есть.

6.4.1. Банковские выписки (автообработка)

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

Как разбирать поступления по безналу: очередь платежей, привязка платежа к клиенту, сводные реестры приёмщиков платежей, вкладка «Банк» в карточке клиента и работа с телефона.

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

Модуль автоматического приёма и зачисления платежей из банковских выписок. Письма с CSV/TXT-вложениями приходят на собственный почтовый ящик bank@вашдомен.ru (на почтовом сервере компании), парсер раскладывает операции в очередь модерации, matching сопоставляет с клиентами по 4 стратегиям (ИНН/лицевой счёт/назначение/fuzzy), оператор подтверждает или система автоматически зачисляет high-confidence матчи. Для юр.лиц генерируются PDF счёт-фактуры и акты (WeasyPrint), опционально загружаются в GCS и отправляются клиенту на email через noreply@вашдомен.ru.

Полная карта URL:

Архитектура (8 фаз)

  1. SmitMailServ на demo-сервере сервер приложения — 4 ящика (bank/noreply/info/support) на почтовом поддомене, MX/SPF/DKIM/DMARC в cloudns.net
  2. IMAP-приёмник (billing/services/imap_client.py) — Celery beat bank-statements-pull ежечасно, реально работает в час/минуту из BANK_PULL_SCHEDULE_HOUR/MINUTE (default 6:00)
  3. Парсеры (billing/services/bank_parsers/) — sber.py (TXT, cp1251, разделитель ;), alfa.py (CSV, cp1251, разделитель \t), dispatcher.py определяет формат по filename + первым байтам
  4. Matching (bank_matching.py) — 4 стратегии в порядке приоритета: innaccountpurposefuzzy (отключаем для prod). AmbiguousMatch исключение если несколько кандидатов — операция уходит в очередь модерации
  5. Credit (bank_credit.py) — transaction.atomic + select_for_update на AdminAccounts, kill-switch BANK_AUTO_CREDIT_ENABLED (default OFF), auto-unblock b_negbal при ostatok ≥ 0
  6. PDF счёт+акт (bank_documents.py, WeasyPrint) — атомарная нумерация СЧ-2026-NNNN/АКТ-2026-NNNN через BankDocumentCounter, опциональная GCS-загрузка, учёт per-abonent настроек (send_act, auto_account, next_auto_acount)
  7. Уведомления (bank_notifications.py) — Telegram-сводка по unmatched с anti-spam (cache 24h) + email клиенту с PDF-attached (до 8MB)
  8. Admin UI — четыре страницы раздела

Главная страница настроек

Настройки модуля автообработки выписок

Структура страницы:

Все тогглы (детальное описание)

КлючDefaultНазначение
BANK_AUTO_CREDIT_ENABLEDfalseГлавный kill-switch автозачисления. Без него модуль работает в режиме «модерация-только»
BANK_AUTO_GENERATE_DOCSfalseАвто-генерация PDF счёт+акт после credit (только для юр.лиц)
BANK_EMAIL_TO_ABONENTfalseОтправлять email клиенту со ссылкой/PDF attached
BANK_NOREPLY_FROMnoreply@вашдомен.ruFROM-адрес для писем клиентам
BANK_TG_ALERT_ENABLEDtrueTelegram-сводка по unmatched-платежам
BANK_TG_ALERT_CHAT_ID / BANK_TELEGRAM_ALERT_CHAT_IDChat ID (priority: TG_ → TELEGRAM_); thread_id опционально
BANK_TG_ALERT_MIN1Минимум pending для алерта
BANK_PULL_SCHEDULE_HOUR/MINUTE6/0Час+минута ежедневного забора писем (Celery beat ежечасно с фильтром ±10мин)
BANK_DOC_DEFAULT_SEND_DAY0День месяца отправки акта если у клиента не задан next_auto_acount. 0 = выпускать сразу
BANK_DOC_UPLOAD_GCStrueKill-switch GCS-загрузки PDF
BANK_CREDIT_WARN_AMOUNT50000Сумма ₽ выше которой 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-счётчик) | Статус (активен/выключен) | Заметки | Действия (редактировать/удалить).

Модалка «Добавить банк»:

Добавление нового банка (например, Тинькофф):

  1. Создать парсер в billing/services/bank_parsers/<slug>.py — наследовать от BankParser, реализовать parse(content: bytes) → List[ParsedOperation]
  2. Зарегистрировать в billing/services/bank_parsers/__init__.py::detect_and_parse() — добавить ветку определения формата
  3. Через UI «Добавить банк» создать BankParserBinding с новым parser_slug
  4. Whitelist в настройках обновится автоматически (читает из BankParserBinding)

Защита от потери данных: при удалении банк-парсера BankStatementImport с этим email_domain в БД сохраняются (FK не настроен). Новые письма с домена будут игнорироваться. Восстановить — повторное добавление с тем же доменом.

6.4.3. Очередь модерации

Очередь модерации платежей

Ключевая страница для финансиста-оператора: через неё проходит 50–100 платежей в день. Один платёж разбирается в один клик через массовое действие или в два — через модальное окно.

Возможности

Credit-модалка (детально)

При клике «Зачислить» fetch'ит /admin/finance/bank_queue/<id>/credit_preview/ и собирает модалку с:

Onboarding-tooltip

Onboarding-tooltip 4 шага

При первом визите показывает 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 разных клиентов, и их оплаты уже зачислены другим каналом. Привязать перечисление к одному клиенту нельзя, а разнести повторно — задвоить деньги. Поэтому оно получает статус «Сводный реестр», уходит из очереди ручного разбора и остаётся в журнале как поступление на расчётный счёт.

Такие платежи были самыми крупными в очереди, и оператор упирался в них первыми. После разделения очередь ручного разбора стала посильной:

Очередь ручного разбораПлатежейСумма
До разделения692 439 244,60 ₽
После51136 836,00 ₽
Вынесено в «Реестры»182 302 408,60 ₽

Как отличается реестр от обычного платежа

flowchart LR
  P["Платёж из выписки"] --> A{"ИНН плательщика
в списке приёмщиков?"} A -->|"нет"| ORD["Обычный платёж
идёт на сопоставление"] A -->|"да"| B{"В назначении есть
признак реестра?"} B -->|"нет"| ORD B -->|"да"| REG["Сводный реестр"]

Признаков должно быть два сразу. Одного ИНН мало: со счёта того же банка приходят и обычные платежи юрлиц-клиентов — их распознавание пропускает дальше, на сопоставление. Признаки реестра в назначении: «ЭЛ.РЕЕСТР», «ПО ПЛАТЕЖАМ С …», «за приём платежей».

Список ИНН приёмщиков — настройка BANK_AGGREGATOR_INNS в модуле, а не константа в коде: появится третий приёмщик — оператор добавит его сам. По умолчанию там ПАО Сбербанк и РНКО «Единая касса».

Что даёт разбор назначения. Из строки вытаскивается количество оплат и период, и в списке видно содержание перечисления — «138 платежей за 01.06.2026». Это основа для сверки: приёмщик перечислил столько-то оплат за такой-то день, и это сравнимо с тем, что разнесено по клиентам в биллинге. Расхождение здесь означает либо потерянные деньги, либо двойное зачисление.

Разбор очереди, организации и аудит

Очередь модерации: чипы статусов со счётчиками, поиск, период, суммовой итог, колонка организации

Аудит модуля 24.08.2026 показал, что очередь стояла не из-за неудобств интерфейса, а из-за трёх дефектов.

Привязка платежа: форма раскрывается прямо под строкой, видны соседние платежи

Поиск клиента идёт по ФИО или названию, номеру договора, телефону, e-mail, ИНН и номеру клиента. Клиенты с совпавшим ИНН поднимаются в начало списка.

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

Видно сам платёж — сумму, дату, банк, плательщика с ИНН и назначение — и кнопки-подсказки с номерами из назначения: клиент часто пишет туда номер договора. Если ИНН плательщика в базе не найден, реквизиты подтягиваются из ФНС через DaData: название, адрес, руководитель и кнопка «Искать по названию из ФНС».

Организация платежа

Импорт и операция запоминают юрлицо-получателя — оно определяется по расчётному счёту из выписки. В очереди и журнале появилась колонка «Орг.», списки скоупятся переключателем организации в шапке и правами сотрудника.

Счёт и акт теперь выписываются от того юрлица, на чей счёт пришли деньги. У каждого юрлица своя серия номеров документов: сквозная нумерация оставляла бы в нумерации одной компании дыры на местах документов другой.

Флаги расхождений в сопоставлении

Три случая помечаются значком и подсветкой строки: совпадение по похожести ФИО, один ИНН у разных клиентов, расхождение ФИО плательщика и клиента. Такие строки не попадают в массовое выделение — их разбирают по одному. При установке галочки «выбрать все» оператор видит, сколько платежей пропущено и почему.

Поиск, период, постраничный вывод и итоги

Панель управления — в одну строку. Поиск, выбор периода и размер страницы сужены так, чтобы вместе с кнопкой «Применить» и инструментами раздела (горячие клавиши, настройка колонок, «Журнал» импортов, «Настройки») уместиться в одну линию. Итог по выборке прижат к правому краю той же строки.

Журнал аудита

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

Вкладка «Банк» в карточке клиента

Вкладка «Банк» в карточке клиента

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

На телефоне

Очередь модерации на телефоне: карточки вместо таблицы

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

6.4.4. Журнал импортов

Журнал импортов выписок

Полный лог писем от банков с возможностью отладки. По умолчанию показывает последние 30 дней (защита от бесконечной выдачи при N тысячах импортов).

Фильтры в одну строку: Банк (Альфа/Сбер/Неизвестно/Все) | Статус (Новые/Разобранные/Ошибки/Без вложений) | Период (7д/30д/90д/Все) | кастомный date-range. Meta-bar над таблицей показывает текущий период + количество найденных записей.

Колонки: # | Получено (datetime) | От (email) | Тема | Банк (chip) | Файл (filename) | Статус (с иконкой) | Операций (всего / сматч. / зачисл.) | Действия.

Действия:

Статусы письма-импорта

Колонка «Статус» в журнале — это статус письма с выпиской (модель BankStatementImport, набор IMPORT_STATUS_CHOICES). Всего 5 значений:

Статус (UI)КодКогда выставляется
🟡 НовыйnewДефолт. Письмо получено по IMAP, вложение сохранено, но ещё не разобрано парсером
🟢 РазобранparsedПарсер успешно прочёл вложение и создал записи BankStatementOperation
🔴 Ошибка парсингаerrorПарсер упал на файле — текст ошибки сохраняется в поле parser_error, виден при наведении
⚪ Без вложенийemptyВ письме нет файла выписки (.csv/.txt)
⚪ ПропущенskippedПисьмо не от банка — домен отправителя не входит в whitelist «Банки и парсеры»

Как меняется статус: «Новый» → «Разобран»

Переход выполняет фоновая задача Celery, оператор в нём не участвует. Цепочка:

  1. bank-statements-pull (Celery beat, ежечасно) — приёмник billing/services/imap_client.py читает UNSEEN-письма из ящика bank@вашдомен.ru и создаёт BankStatementImport со статусом new.
  2. 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 не выполняется. Что проверить:

Шрифтовая пара для PDF

В Брендинге → карточка «Документы» → селект «Шрифтовая пара для PDF». 5 кириллических вариантов:

⚠ Ограничение WeasyPrint: в Docker-контейнере нет доступа к fonts.googleapis.com, поэтому в PDF — fallback на DejaVu Sans. Шрифты применятся только при печати через браузер либо при переходе на Playwright/Chrome headless для PDF-генерации. Поле font_pair сохраняется корректно.

Per-abonent настройки документов

Учитываются существующие поля клиента (вкладка «Настройки» в карточке):

Если у юр.лица оба флага OFF — документы не генерируются даже при BANK_AUTO_GENERATE_DOCS=true. Если next_auto_acount не задан, используется fallback на BANK_DOC_DEFAULT_SEND_DAY (день месяца).

Единое оформление всех четырёх страниц

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

Банковские выписки — очередь модерации (единые компоненты)

Журнал импортов на SmitTable — настройка колонок

SmitConfirm — подтверждение опасного забора писем

Привязка платежа раскрытием строки (по образцу Xero)

6.4.5. Почтовый сервер (SmitMailServ)

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

Почтовый сервер — Обзор

Обучающее видео 3:00

Где заводить ящики, зачем домену организация, что делает роль ящика и куда смотреть, когда «почта не работает».

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

Вкладка «Обзор»

Состояние сервера, настройки API, защищённые ящики, DKIM/SPF/DMARC.

Селект «Основной домен»

Вкладка «Ящики»

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

Список ящиков: тулбар, организации, роли

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

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

Роль — это ответ на вопрос «что этот ящик делает для биллинга». Назначенная роль показана подписью, остальные остаются значком с подсказкой: в списке на сотню строк важно видеть включённое, а не перечень возможного.

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
Роль настраивает ящик сама. При включении роли параметры IMAP и SMTP, защита и расписание разбора прописываются автоматически — вручную ничего дописывать не нужно. Роль занята одним ящиком в организации: назначили другому — с прежнего она снимается.
На телефоне

Сверху остаётся то, за чем в раздел заходят: выбор домена и «Добавить». Ниже — поиск, «Фильтры» и обновление в одну строку; фильтр по типу ящика открывается шторкой снизу. Таблица превращается в карточки — по строке на ящик, без горизонтальной прокрутки.

Список ящиков на телефоне
Телефон: домен и «Добавить», под ними поиск с «Фильтрами».
Шторка фильтров списка ящиков
Шторка «Фильтры»: персонал и системные ящики.
flowchart TB
  subgraph D["Десктоп"]
    T["Одна строка тулбара:
домен · тип ящика · поиск · колонки · добавить"] TB["Таблица:
настраиваемые колонки, роли в строке"] T --> TB end subgraph M["Телефон"] P["Домен + Добавить"] S["Поиск + Фильтры + Обновить"] SH["Шторка: тип ящика"] C["Карточки ящиков"] P --> S --> C S -.-> SH end D -.->|те же элементы, другая раскладка| M

Добавление ящика (кнопка «Добавить ящик»):

Модалка «Добавить ящик»

Вкладка «Админы доменов»

Админы доменов

Управление доменными админами 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
Как читать схему. Письмо снаружи проходит приём, антиспам и попадает в хранилище; сотрудник видит его через веб-почту. Биллинг подключается к тем же частям: читает обращения и выписки по IMAP, отправляет уведомления через SMTP. Поэтому красная строка «Приём и отправка» означает и молчащие уведомления, а красное «Хранение и чтение» — необработанные обращения.

Письма доходят, а не в спам — четыре проверки на каждый домен: подпись писем, разрешение на отправку, защита от подделки и запись приёма почты. Все зелёные означают, что письма с этого домена принимают Gmail, Mail.ru и Яндекс; красная — письма могут уходить в спам, и настраивать её нужно в разделе «Домены и DNS».

Здоровье почтового сервера
Состояние частей почты и очередь отправки.
Проверки доставляемости по домену
Четыре проверки на домен: подпись, разрешение, защита, приём.

Колонка «Писем» в списке ящиков

В списке ящиков рядом с квотой показывается «непрочитанных / всего». Клик по счётчику открывает ящик в почте. Пока сбор не отработал, вместо чисел стоит прочерк — это не то же самое, что «писем нет».

Список ящиков с колонками «Квота» и «Писем»

Список ящиков: роли, владелец, занятое место и счётчик писем.

Как это устроено внутри. Количество писем и занятое место считаются обходом почтовых каталогов по расписанию, а не запросом при каждом открытии страницы: у сотни ящиков это заняло бы секунды на каждый рендер. Поэтому значения обновляются с задержкой, равной выбранному интервалу сбора.

6.4.5А. Домены и DNS (Cloudflare)

URL: /admin/settings/dns/ — управление DNS-зонами через Cloudflare API прямо из биллинга: зоны и записи (CRUD), сценарии в один клик и диагностика.

Cloudflare API из России. Запросы к Cloudflare идут через прокси — прямой доступ с российских IP блокируется.

6.4.6. Автонастройка почтовых ящиков и DNS

Единый сервис провижинга (billing/services/mailbox_provisioning.py) создаёт почтовый ящик, прописывает DNS-записи и заполняет настройки подключения — одной кнопкой. Работает везде, где системе нужен ящик.

Требования. Кнопка «Автонастроить ящик» появляется, если включён модуль «Почтовый сервер» и настроен Cloudflare API для домена организации (раздел «Домены и DNS»). Иначе поля SMTP/IMAP заполняются вручную.

Что делает автонастройка

  1. Регистрирует домен в почтовом сервере (идемпотентно — повторный запуск безопасен).
  2. Создаёт ящик <имя>@<домен> с сгенерированным паролем. Если ящик уже существует — переиспользует его пароль, ничего не сбрасывая.
  3. Прописывает DNS-записи почты в Cloudflare: A (mail.домен), MX, SPF, DKIM, DMARC.
  4. Заполняет параметры подключения (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 и другие зарезервированные логины; лимит — один ящик на домен.