13 KiB
Пассивный доход брокерского счёта
Пассивный доход отвечает на вопрос «сколько брокер сообщил исполненными
купонами и дивидендами за выбранный период». Пользователь открывает
/accounts/:accountId/income из обзора счёта или
общий доход по доступным счетам.
Экран показывает итоги в RUB и отдельную карточку каждой
включённой выплаты. Источником служат исполненные операции,
а не изменение цены портфеля и не календарь будущих выплат.
Суммы сохраняют знак брокерского денежного движения. Налоговые операции не включаются; результат не называется суммой до или после налогов, инвестиционной эффективностью или налоговым расчётом.
Период и данные
GET /api/v1/brokerage-accounts/:accountId/income-summary возвращает текущий месяц по сегодняшнюю дату для компактного блока обзора. Он не зависит от периода, который пользователь ранее выбрал на странице аналитики.
GET /api/v1/brokerage-accounts/:accountId/income-analytics?from=YYYY-MM-DD&to=YYYY-MM-DD возвращает полный результат. Даты задают включительный период в Europe/Moscow; без них применяется текущий месяц. Период не может быть будущим или обратным. Максимальная длительность периода не ограничена.
Оба запроса требуют Bearer token и используют обычные ответы о неподключённом T-Bank, отклонённом токене, недоступном счёте и временной недоступности источника.
Выбор периода и состояния страницы
В блоке «Период» два календарных поля Mantine DateInput показывают даты в формате
ДД.ММ.ГГГГ. Календарный выбор и ручной ввод изменяют только черновик. Кнопка
«Применить» или отправка формы с клавиатуры проверяют видимый текст и передают допустимые
даты в URL как from=YYYY-MM-DD&to=YYYY-MM-DD. До применения результат сохраняется; отдельной
подписи периода под фильтрами нет. Открытие URL и навигация назад восстанавливают
применённый период.
Пустая, несуществующая или будущая дата получает ошибку у своего поля; обратный диапазон — у поля «По». Некорректный текст не заменяется последней допустимой датой при потере фокуса, не меняет URL и не отправляет запрос. Календарь учитывает допустимую соседнюю дату и сегодняшний день в Europe/Moscow. «Сбросить» сразу применяет текущий московский месяц по сегодняшний день, восстанавливает оба поля и очищает ошибки, даже если изменён только черновик.
При первой загрузке или новом периоде без сохранённых данных показан каркас страницы. Пустой результат объясняет отсутствие исполненных купонов и дивидендов, сохраняя фильтры и налоговое пояснение. Ошибка запроса или нарушение принадлежности выплат даёт локальное состояние недоступности без действия повтора; чтение восстанавливается автоматически. При фоновом обновлении того же периода сохранённый ответ и черновик остаются видимыми без индикации обновления и технического предупреждения. Неполнота применённого периода обозначается состоянием самого результата.
На узком экране поля и действия идут вертикально; все карточки выплат остаются в общем потоке страницы без раскрытия или внутренних областей прокрутки.
Какие выплаты входят в результат
- Backend проверяет доступ локально и читает сохранённые операции. Фоновая загрузка должна завершить все страницы; ошибка страницы или повреждённая цепочка курсоров не подтверждают полноту.
- Только точные типы купона и дивиденда источника формируют результат. Суммы остаются точными десятичными строками в RUB; отрицательные корректировки сохраняют знак. Выплаты в других валютах не участвуют. Налоги, комиссии, сделки, переводы, погашения и переводы дивидендов не входят в доход.
- Итоги, временные интервалы и разбиение по инструментам считаются только в RUB. Система не загружает другие периоды ради сравнения полученного дохода с выбранным.
- Временные интервалы по-прежнему приходят с backend: дни для 1–45 дней, недели для 46–180 и месяцы для более длинного периода, включая пустые интервалы. Страница дохода не строит из них график или текстовую динамику; ответ API не меняется.
- Раздел «Выплаты» показывает карточки выплат в исходном порядке
entries. В отдельном счёте каждая выплата — отдельная карточка. В режиме «Все счета» выплаты одного инструмента, дня и точного типа образуют группу, если их две и более (правила группировки). Группа стоит на месте первой выплаты; каждая строка счёта показывает название счёта и свою сумму со знаком. Визуальный итог группы — точная сумма в RUB по показанным выплатам; он скрыт, если полнота периода неcomplete, или у выплаты нет суммы, или сумма равна нулю. Это клиентский расчёт и не заменяет серверные итоги аналитики дохода, которые по-прежнему приходят из ответа API и не пересчитываются. Описание, дата, доступные идентификаторы инструмента и сумма со знаком видны в каждой выплате. Дополнительный запрос за составом не нужен.
Полнота и принадлежность выплат
Доходы читают сохранённые операции и coverage в согласованной транзакции. Только выбранный период определяет готовность результата. Неполный период не получает окончательных итогов. Подтверждённый пустой период отличается от ещё не загруженного. При смене периода прежний snapshot не показывается под новым названием.
Ручная сверка полного периода сохраняет весь прежний результат до успешной атомарной публикации всех необходимых интервалов и счетов. История счёта может ещё догружаться после готовности выбранного месяца.
Каждая запись income-analytics.entries содержит обязательный instrumentKey,
равный key соответствующей строки instruments. Backend вычисляет этот ключ
один раз при подготовке записей дохода и использует его же для группировки.
Приоритет UID, FIGI, ticker/type и ID операции остаётся
серверным правилом; клиент воспринимает ключ как непрозрачную строку.
Это поле принадлежит ответу аналитики; общий журнал операций его не требует.
Backend обеспечивает принадлежность выплат и receipt count при построении entries и instrument groups из одного набора данных. Frontend доверяет типизированному contract, не восстанавливает формулу идентификации и не выполняет второй consistency validator. Полностью пустой ответ допустим. Состав и исходный серверный порядок записей и знак сумм сохраняются; серверные денежные итоги frontend не пересчитывает (визуальный итог группы в режиме «Все счета» отдельный, см. выше). Стабильный ID в пределах подключения и счёта определяет одну операцию: повторная сверка обновляет её без двойного учёта. Одинаковые ID разных счетов остаются разными выплатами. Изменение источника логотипа позволяет заново показать изображение после буквенной заглушки.
Будущие события и ограничения
На странице дохода нет блоков «Динамика» и «Ближайший прогноз», блоков
сравнения периодов и сообщений об их недоступности. Она не запрашивает
/events и не зависит от его доступности. Самостоятельная страница
«Будущие события» по-прежнему доступна из обзора
выбранного счёта и сохраняет прежнее поведение. Будущие выплаты
не включаются в итоги полученного дохода.
Аналитика читает сохранённую историю операций и не рассчитывает налоги, доходность (её показывает результат инвестирования), или итоги по нескольким валютам.
Основное проверяемое поведение — в спецификации дохода, точная форма ответа — в HTTP API. Не следует использовать календарь будущих событий для восстановления состава уже полученного дохода.