Банковские выписки
Автоматический разбор банковских выписок: банки и парсеры, очередь модерации спорных платежей, журнал импортов.
Содержание раздела
- Банковские выписки (автообработка)
- Архитектура (8 фаз)
- Главная страница настроек
- Все тогглы (детальное описание)
- IMAP-приёмник и whitelist
- Telegram-алерты по unmatched
- Банки и парсеры
- Очередь модерации
- Возможности
- Credit-модалка (детально)
- Onboarding-tooltip
- Путь платежа: от письма банка до баланса клиента
- Сводные перечисления приёмщиков платежей
- Как отличается реестр от обычного платежа
- Разбор очереди, организации и аудит
- Привязка платежа: контекст и данные ФНС
- Организация платежа
- Флаги расхождений в сопоставлении
- Поиск, период, постраничный вывод и итоги
- Журнал аудита
- Вкладка «Банк» в карточке клиента
- На телефоне
- Журнал импортов
- Статусы письма-импорта
- Как меняется статус: «Новый» → «Разобран»
- Диагностика: статус долго не меняется
- Шрифтовая пара для PDF
- Per-abonent настройки документов
- Единое оформление всех четырёх страниц
Банковские выписки (автообработка)
Как разбирать поступления по безналу: очередь платежей, привязка платежа к клиенту, сводные реестры приёмщиков платежей, вкладка «Банк» в карточке клиента и работа с телефона.
Модуль автоматического приёма и зачисления платежей из банковских выписок. Письма с 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/1234567890/42 → автоматически заполняет chat_id=-1001234567890 и thread_id=42. Поддерживаются 3 формата: /c/<chat>/<thread>, https://t.me/<username>, числовой -100....
Банки и парсеры
Регистр банков с привязкой к парсерам и 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 не настроен). Новые письма с домена будут игнорироваться. Восстановить — повторное добавление с тем же доменом.
Очередь модерации
Ключевая страница для финансиста-оператора: через неё проходит 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, СУММА 98500.00, КОЛ-ВО 112, ЭЛ.РЕЕСТР EPS…
За такой строкой стоят 112 разных клиентов, и их оплаты уже зачислены другим каналом. Привязать перечисление к одному клиенту нельзя, а разнести повторно — задвоить деньги. Поэтому оно получает статус «Сводный реестр», уходит из очереди ручного разбора и остаётся в журнале как поступление на расчётный счёт.
Такие платежи были самыми крупными в очереди, и оператор упирался в них первыми. После разделения очередь ручного разбора стала посильной:
| Очередь ручного разбора | Платежей | Сумма |
|---|---|---|
| До разделения | 70 | 1 250 000,00 ₽ |
| После | 52 | 140 000,00 ₽ |
| Вынесено в «Реестры» | 18 | 1 110 000,00 ₽ |
Как отличается реестр от обычного платежа
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. В шапке сумма зачисленного и переход в очередь, отфильтрованную по этому клиенту.
На телефоне
На телефоне строка разворачивается карточкой «поле — значение», сумма показана крупно, кнопки во всю ширину. Чекбоксы массового выбора на телефоне скрыты: платежи здесь разбирают по одному.
Журнал импортов
Полный лог писем от банков с возможностью отладки. По умолчанию показывает последние 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) — то же в виде модалки / слайд-панели.