Выписки из других банков (T23)¶
statements.py принимает выписки, которые клиент загружает в ответ на запрос данных, и добавляет их к нашему счёту при расчёте качества данных и лимита. Зачем: у клиента уровня PARTIAL или THIN часть бизнеса идёт через другие банки (SPEC §5.1), и без его документов банк видит только часть оборотов.
Когда просим выписку¶
- Данные
THIN. После стоп-факторов и скорингаdecide(workflow.py) возвращает статусneeds_data, а неin_review. Вrequested_documents— «Выписка по расчётному счёту в другом банке за последние 12 месяцев». Балл и причины маршрута в решении есть, предложений нет: без выписки лимит по потоку не считается. Клиент видитDataQuality.client_message(«…понадобятся выписки из других банков»). - Запрос сотрудника. Андеррайтер запрашивает данные (
request_data, T20,STAFF_ACTIONS.md), например у клиентаPARTIAL, у которого покрытие выручки ниже 70%. Код причины —statement_needed.
У клиента PARTIAL, который получил предложения автоматически (offered), загрузить выписку нельзя: в таблице статусов SPEC §13 нет перехода offered → enriching. Клиент может подать новую заявку.
Что делает клиент¶
| Действие | API | Переход |
|---|---|---|
| Загрузить выписки | POST /api/v2/applications/{id}/statements, multipart/form-data: files (до 5 файлов по 2 МБ) и revision |
needs_data → enriching |
| Продолжить без выписки | POST /api/v2/applications/{id}/statements/skip {"revision"} |
needs_data → enriching |
Файл, который не удалось распознать, выписка на другой ИНН, файл, который уже загружен, и больше 5 выписок на заявку — ответ 422 с текстом для клиента, статус не меняется. Без выписки заявка THIN пересчитывается как есть и уходит андеррайтеру (route_data_thin); повторно выписку система не просит.
Пересчёт¶
Заявка после ответа клиента — в enriching без аренды; worker берёт её через claim_resumed (WORKFLOW.md). Источники заново не опрашиваются, если в прошлый раз ответили все обязательные: берутся сохранённые ответы. Иначе каждая выписка означала бы новый запрос кредитной истории, а частые запросы БКИ снижают балл самому клиенту. Если обязательный источник был недоступен, источники опрашиваются заново.
Что меняют выписки:
| Что | Чем считается | С выписками |
|---|---|---|
| Качество данных (SPEC §5.1) | data_quality (T09) |
По нашему счёту вместе с выписками: обороты складываются по месяцам. Растут история (месяцы до открытия нашего счёта), покрытие выручки, регулярность |
| Лимит по денежному потоку и обороту (SPEC §9.1) | cash_flow (T16) |
Тоже по сумме нашего счёта и выписок, с уровнем данных, пересчитанным с выписками |
| Стоп-факторы, флаги T14, признаки скоринга, балл | evaluate_stop_factors, features_from_responses, score |
Не меняются: только наши данные и госисточники. Карта обучена на нашем счёте, а документ клиента менее надёжен (порядок надёжности источников, SPEC §5.1) |
| Маршрут | route_application(..., statements=True) |
Всегда андеррайтер, причина route_statement_upload: документ клиента проверяет человек |
| Факты | statement_facts |
operating_inflows_12m и statement_months с источником statement_upload и уровнем надёжности client_document, рядом с теми же фактами по нашему счёту |
Событие журнала «Данные из источников собраны…» хранит, сколько выписок учтено (statements_used), уровень данных по одному нашему счёту (own_account_tier) и были ли переиспользованы ответы источников (sources_reused).
Проверки (check_statements)¶
Документы клиента проверяются на согласованность с нашими данными и госисточниками (SPEC §5.1):
| Проверка | Что происходит | Флаг |
|---|---|---|
| Выписка заканчивается больше чем за 3 месяца до последнего полного месяца или позже него | Выписка не учитывается | statement_period |
| Поступления от покупателей за 12 месяцев с учётом выписок выше выручки по ФНС больше чем на 30% | Выписка учитывается | statement_inflows_above_fns |
| ИНН в выписке не совпадает с ИНН заявки | Загрузка отклоняется (422) | — |
Флаги попадают в Decision.flags и маршрут (route_flag_<код>), клиент видит только «Мы проверим загруженные выписки вручную».
Формат файла¶
Пока файл — это JSON с уже распознанной выпиской:
{
"bank_name": "Банк «Пример»",
"inn": "5406000001",
"months": [
{"month": "2025-10", "inflows": {"customers": 850000, "own_transfers": 0, "loans_received": 0,
"founder_contributions": 0, "other": 0},
"outflows": {"suppliers": 600000, "payroll": 120000, "taxes": 30000, "rent": 40000, "loan_payments": 0,
"cash_withdrawals": 0, "own_transfers": 0, "other": 10000},
"average_balance": 200000}
]
}
months — от 1 до 24 месяцев, от старого к новому, в формате MonthlyTurnover из контрактов (те же категории, что у нашего счёта). Модель Statement лежит в statements.py, а не в contracts.py: перенос в контракты — отдельный PR в общую папку (docs/v2/NOTES.md, Unassigned).
Упрощения¶
# MOCK:распознавания нет. Файл уже содержит результат: обороты по месяцам и категориям. В банке клиент загружал бы PDF или файл обмена 1С (1CClientBankExchange), его читала бы модель OCR / разбора с открытыми весами, а каждый платёж относился бы к категории (покупатели, поставщики, зарплата, свои переводы…) классификатором.# SIMPLIFICATION:переводы между нашим счётом и счётом в другом банке остаются в обеих выписках (поступление в одной и списание в другой), поэтому доля операционных поступлений с выписками ниже настоящей. В банке такие переводы сопоставлялись бы и исключались.# SIMPLIFICATION:пороги проверок (3 месяца давности, 30% сверх выручки ФНС) и ограничения загрузки (5 файлов по 2 МБ) — константы вstatements.py, а неconfig/.- Подлинность выписки не проверяется: в банке её подтверждали бы через банк-отправитель или по электронной подписи. Поэтому заявку с выпиской всегда смотрит андеррайтер.
- Файлы не хранятся: хранится распознанная выписка, имя файла, размер и SHA-256 (
loan_applications.statements).