Disputes API — это сервис на Java (Spring Boot), предназначенный для работы со спорами (disputes) в финансовой инфраструктуре. Основные задачи:
- Создание, хранение, обновление и завершение (закрытие) споров;
- Взаимодействие с внешними сервисами (такими как PartyManagement, Invoicing, FileStorage, Dominant, TgBot, ProviderPayments и др.) для получения/отправки данных или выполнения операций в рамках процесса урегулирования споров;
- Обработка уведомлений от внешних систем, а также отправка callback-уведомлений;
- Плановое (scheduled) выполнение задач, связанных со статусами споров, их обработкой, оповещениями и т.д.;
- Безопасность и авторизация через сервис Bouncer (или TokenKeeper), а также конфигурация доступа.
Ниже описан полный жизненный цикл спора по финансовой транзакции
-
Инициирование спора
- Отправная точка: кто-то (чаще всего мерчант или покупатель, действующий через мерчанта) решает оспорить платёж. Причин может быть множество: покупатель недоволен качеством товара, не узнаёт транзакцию, считает, что деньги списали ошибочно и т.д.
- Проверка возможности спора: система смотрит, не вышли ли сроки давности, действительно ли существует такая оплата, не было ли уже открыто слишком много споров по этому же платежу. Если всё валидно, спор считается «принятым» к рассмотрению. В противном случае система откажет или известит, что спор нельзя открыть.
- Запись в систему: создаётся «карточка» спора — системная запись с информацией о платеже, сторонах, сумме, возможных причинах и т.д. Все изменения по этому спору будут фиксироваться здесь же.
-
Предварительная проверка
- Внутренний анализ: сразу после создания система может проверить статус платежа (например, не отменён ли он уже, не возвращены ли средства), сверить данные об отправителе и получателе, убедиться, что оплата прошла по корректным реквизитам.
- Уведомление сторон: система сообщает ключевым участникам (часто это сам мерчант, платёжный провайдер, иногда — административный персонал), что спор открыт. Если нужно, рассылаются письма, push-уведомления или другие сигналы.
-
Сбор доказательств и материалов
- Загрузка файлов: могут понадобиться копии чеков, договоров, переписки. Участники спора (мерчант, администратор) передают их системе, которая хранит всё это, чтобы в дальнейшем при рассмотрении был доступ к документам.
- Проверка прав: система разрешит загружать или просматривать документы только тем, у кого достаточно полномочий. Например, мерчант видит все файлы по своему магазину, администратор — по любому спору, а третьи лица — нет.
-
Изменение статуса по ходу рассмотрения
- Промежуточные статусы: спор может долго находиться «в ожидании» ответа от внешнего провайдера, решения мерчанта или покупателя. В этот период система регулярно проверяет, не пришло ли новое событие (например, «провайдер подтвердил транзакцию» или «покупатель отозвал претензию»).
- Автоматические триггеры: если долго нет ответа, система может автоматически изменить статус: например, «срок ответа истёк — спор закрыт в пользу мерчанта» или «провайдер не подтвердил операцию, средства возвращены».
- Вмешательство администратора: если возникают нештатные ситуации (спор «завис» или есть противоречивые данные), администратор вручную меняет статус или даёт указание: «Вернуть деньги», «Отказать в возврате», «Продлить время ожидания» и т. п.
-
Взаимодействие с внешними системами (платёжные провайдеры и т.д.)
- Входящие уведомления: провайдер может прислать «обратный вызов», сообщив о принятом решении (например, банк подтвердил транзакцию). Система обработает этот сигнал и обновит спор: «претензия отклонена», «деньги зарезервированы для возврата» и т. п.
- Исходящие уведомления: при каждом ключевом событии (начало спора, его завершение, возврат средств) система отправит сигналы тем, кто должен знать (другим сервисам, боту поддержки, дополнительным каналам).
- Повторные попытки: если уведомление не доставлено (например, проблемы с сетью), система запланирует новые попытки через некоторое время. Аналогично и провайдер может повторно присылать уведомления, если не получил ожидаемый ответ.
-
Плановые проверки и автоматизация
- Регулярные задачи: чтобы никто не «забыл» спор, система периодически просматривает все споры и смотрит, нет ли затянувшихся статусов. Если обнаружит, что спор «висит» без ответа, может автоматически завершить его по заранее заданным правилам или повторно отправить запрос провайдеру.
- Напоминания: если у спора есть крайний срок, по истечении которого надо принимать решение, система может уведомить администратора или мерчанта, что «время вышло, нужно либо предоставить доказательства, либо будет автоматический отказ».
-
Завершение спора
- Успешное разрешение: после рассмотрения всех аргументов и доказательств принимается окончательное решение: вернуть средства, отказать в возврате и т. д. Система переводит спор в финальный статус, где уже ничего изменить нельзя.
- Денежные операции: если результатом спора стал возврат (частичный или полный), может быть инициирован процесс возврата через платёжного провайдера. Система зафиксирует, что средства отправлены обратно, закроет спор и уведомит участников.
- Отказ в удовлетворении: если спор признан несостоятельным, система тоже закрывает его, помечает как «завершён» с результатом «отказано», уведомляет стороны и прекращает дальнейшие действия.
-
Специальные случаи и ошибки
- Конфликт статусов: бывает, что пока одна сторона обновляет спор, другая успевает изменить его в другом процессе. Система может обнаружить расхождение и либо выдать ошибку, либо синхронизировать данные по определённым правилам.
- Непредвиденные ситуации: если при проверке выяснится, что платеж уже давно отменён или не существовал, система может отклонить открытие спора или досрочно его завершить.
- Истёкшие сроки: если спор слишком «старый», система откажет в рассмотрении с пояснением, что срок давности для претензий уже прошёл.
- Проблемы доставки: если уведомления или запросы к провайдеру по какой-то причине недоступны, система записывает это и продолжает пытаться доставить информацию в фоновом режиме, пока не сработает лимит попыток или не восстановится связь.
Таким образом, сервис «ведёт» спор по жизненному циклу: от момента, когда кто-то решает, что с оплатой что-то не так, до окончательного решения о том, возвращать ли деньги и кому. При этом система старается учесть все возможные сценарии — от успешного автоматического завершения до форсированных действий администратора или автоотказа при истечении срока. Все изменения в споре журналируются и при необходимости могут быть пересмотрены, а доступ к управлению и просмотру контролируется уровнем прав, чтобы никто случайно или намеренно не нарушил процедуру.
Ниже представлена сводка (обзор) структуры проекта и ключевых сценариев бизнес-логики. Документация предназначена для того, чтобы помочь в понимании основных модулей, сервисов и сценариев обработки споров (disputes) и взаимодействующих с ними компонентов.
Пакеты в src/main/java/dev/vality/disputes можно условно разделить на несколько крупных блоков:
- admin — функциональность, связанная с административными операциями, колбэками и управлением (например,
AdminManagementDisputesService,CallbackNotifierи т.п.). - api — публичные API-интерфейсы и делегаты (
DisputesApiDelegate,DisputesApiDelegateService), конвертеры моделей, а также сервисы, работающие с основным REST/HTTP-интерфейсом (например,ApiDisputesService,ApiNotificationService). - config — конфигурация Spring (бины, доступ, настройки кэширования, сетевых запросов, конфигурация http-клиентов).
- dao — доступ к базе данных (Data Access Objects) и модели для хранения (например,
DisputeDao,FileMetaDao,NotificationDao). - exception — классические Java-исключения, связанные с нарушением логики: авторизация, не найденные сущности, неверный статус, итд.
- flow, merchant, polling, provider и schedule — модули, отвечающие за различные аспекты бизнес-процессов и интеграций (обработка статусов, callback-уведомлений, плановые задачи, интеграция с внешними провайдерами).
- security — модули, отвечающие за авторизацию и работу с контекстом Bouncer/TokenKeeper.
- service — основная логика (бизнес-сервисы) по обработке споров, взаимодействие с внешними системами (InvoicingService, PartyManagementService, FileStorageService и т.п.).
Ниже даётся обзор ключевых сценариев бизнес-логики, где наиболее активно задействованы указанные компоненты.
- Создание спора (merchant/admin, проверка статусов, запись в БД, уведомления).
- Обновление спора (переход статусов, логирование, колбэки, уведомления).
- Административные операции (обзор/поиск споров, форсирование статусов, пересылка доказательств).
- Callback’и от внешних провайдеров (получение, валидация, апдейт статуса).
- Отправка внутренних callback’ов/уведомлений (TgBot, другие системы).
- Плановые задачи (отслеживание “забытых”/ожидающих споров, пересылка неудавшихся уведомлений и пр.).
- Работа с файлами (FileStorageService, DAO для метаданных).
- Безопасность (Bouncer/TokenKeeper, проверка прав, конфиг).
- MerchantDisputesHandler (пакет
dev.vality.disputes.merchant) обрабатывает входящие запросы от мерчанта (черезMerchantServlet). - CreateRequestConverter (там же, в
converter) преобразует входной DTO/JSON в модель, понятную системе. - DisputesService (или
ApiDisputesServiceдля REST-уровня) в пакетеserviceпроизводит дальнейшую обработку, создаёт запись о споре в базе (DisputeDao). - В процессе создаётся запись о споре в БД, возможна валидация статуса платежа (через
InvoicingService,PaymentStatusValidator). - Запускаются дополнительные проверки или уведомления внешним сервисам (в частности, через
BouncerServiceмогут проверяться права, а черезTgBotServiceможет уйти сообщение-уведомление).
Итого: Сценарий “Создание” фокусируется на принятии параметров спора, валидации необходимых полей (статус платежа, возможность спора), записи в БД и вызове callback’ов (при необходимости).
- Логика изменения статуса (например,
ApiDisputesServiceилиAdminManagementDisputesService) вызывает метод изDisputesService. DisputesServiceпроверяет текущий статус спора, сверяет его со статусом, поступившим от внешнего сервиса (или админской панели), а также осуществляет валидацию перехода.- Далее через DAO-слой обновляется статус и пишется в лог (а при некоторых переходах — пересчитываются связанные данные).
- При особых случаях (например, если спор выигран/проигран) может вызываться вызов во внешние системы (уведомления
ApiNotificationService, callback вprovider.payments.callback.ProviderPaymentsCallbackHandlerи т.п.). - Параллельно могут быть запущены плановые процессы (
schedule), которые проверяют “забытые” (зависшие) споры (ForgottenDisputesTask) либо ждут завершения спора (PendingDisputesTask).
Сценарий “Обновление статуса” часто инициируется либо внешней системой (callback), либо администратором, либо при исполнении плановой задачи.
- AdminManagementHandler (в
admin.management) и AdminManagementDisputesService обеспечивают доступ к операциям управления для администраторов. - Доступ к этим методам контролируется через настройки безопасности (
AccessConfig,BouncerServiceImpl). - Администратор может:
- Просматривать споры (фильтрация/поиск через
DisputeDao); - Менять статус спора (например, переводить в “REFUNDED” или “REJECTED” и т.п.), что ведёт к логике из п. 2.2;
- Вызывать переотправку уведомлений, создавать комментарии или загружать дополнительные файлы/доказательства (через
FileStorageService).
- Просматривать споры (фильтрация/поиск через
- Пакет
provider.payments.callback(ProviderPaymentsCallbackHandler,ProviderPaymentsCallbackServlet) занимается приёмом уведомлений от внешних провайдеров. - При приходе callback’а система валидирует соответствие (уникальность, статус, отсутствие дубликатов). Если успешно — обновляет статус спора (или платежа в контексте спора), записывает обновлённую информацию (DAO-слой, например
ProviderCallbackDao), после чего может инициировать дальнейшие действия (запуск chain’ов, нотификаций, обновление invoice-состояния черезInvoicingService). - В случае конфликтов (дублирующие callback’и, конфликт статусов) выбрасываются исключения (
ProviderCallbackAlreadyExistException,ProviderPaymentsUnexpectedPaymentStatusи т.п.) и callback может быть обработан повторно или отклонён.
- CallbackNotifier (и его реализации
DisputesTgBotCallbackNotifierImpl,DummyCallbackNotifierImpl) в пакетеadmin.callback. - При изменении статуса спора (или иных событиях) Disputes API может отправить уведомление (например, в Telegram-бот или в другой внешний сервис).
- Конфигурация, куда отправлять, задаётся в
TgBotConfigи др. - Либо могут быть вызваны методы
ApiNotificationService, которое, в свою очередь, создаёт запись вNotificationDaoи при успешной отправке обновляет статус уведомления. - Параллельно существуют задачи из пакета
schedule(например,NotificationTask), которые периодически проверяют, есть ли необработанные/неотправленные уведомления, и пытаются их доставить повторно.
В пакете schedule сосредоточены регулярные задачи, связанные с обработкой споров и нотификаций:
- CreatedDisputesTask: обрабатывает недавно созданные споры (например, для дополнительных проверок, триггеров).
- PendingDisputesTask: выявляет “зависшие” споры, где ожидается действие от провайдера/внешней системы, и в случае истечения таймеров (конфигурируются в
DisputesTimerProperties) обновляет статус или делает повторные запросы. - ForgottenDisputesTask: обрабатывает споры, у которых сильно просрочен SLA (например, ожидается ответ, а ответа долго нет).
- NotificationTask: пытается повторно отправить уведомления, которые не были доставлены.
- Задачи используют сервисный слой (например,
CreatedDisputesService,PendingDisputesService,NotificationService) и, при необходимости, взаимодействуют с DAO (для получения списка нужных споров/уведомлений) и затем обновляют их статусы.
- В бизнес-процессах по спорам часто требуется загрузка дополнительных материалов (доказательств) — чеки, скриншоты, договоры и т.д.
- В пакете
service.externalестьFileStorageService(иFileStorageServiceImpl), которое через REST/gRPC или иной протокол обращается к внешнему File Storage сервису. - В DAO-слое есть
FileMetaDao, позволяющий хранить метаданные о файлах, связанных со спором. - При загрузке файлов сервис проверяет права пользователя, валидирует формат, сохраняет данные, возвращает ссылку (URL) на скачивание или предпросмотр.
- При разрешении спора администратор или мерчант могут прикреплять/просматривать файлы (логика в
ApiAttachmentsService).
- Пакет
securityсодержит логику работы с Bouncer (или TokenKeeper). AccessService,BouncerServiceиTokenKeeperServiceпроверяют, имеет ли субъект (пользователь, мерчант, админ) право выполнять данную операцию (например, создавать спор, менять статус, смотреть чужие споры).AccessConfigиBouncerPropertiesмогут содержать настройки эндпоинтов, ключей, секретов и т.д.ContextFragmentNameпоказывает, какие именно части контекста проверяются: инвойсы, шопы, операции над платежами и т.д.