2024-08-26 12:31:48 +00:00
|
|
|
|
# disputes-api
|
|
|
|
|
|
|
|
|
|
# Технические особенности
|
|
|
|
|
|
|
|
|
|
Сервисы разделены по модулям, к которым относится данный функционал, будь то `../api/`, `../security/`
|
|
|
|
|
или `../schedule/`
|
|
|
|
|
|
|
|
|
|
Поэтому возможны смежные названия сервисов (как `**AttachmentsService`) , но при этом сервисы работают для разных задач,
|
|
|
|
|
ограниченные рамками модулей
|
|
|
|
|
|
|
|
|
|
Реализовывать отдельное оповещение нет необходимости, потому что закладываемся, что мерчант настроит получение вебхуков
|
|
|
|
|
по ивенту корректировки и `webhook-dispatcher` сам узнает об этом ивенте о пошлет уведомление
|
|
|
|
|
|
|
|
|
|
## Модуль `API`
|
|
|
|
|
|
|
|
|
|
Модуль внешнего доступа для создания диспутов и опроса статуса. Все действия проходят через БД, проактивного запроса к
|
|
|
|
|
провайдерскому `API` не происходит. Создание диспута означает лишь создание записи в БД, решение далее принимается на
|
|
|
|
|
уровне модуля `../schedule/`
|
|
|
|
|
|
2024-08-26 15:47:37 +00:00
|
|
|
|
Перед созданием нового диспута проверяем, существует ли уже какой либо открытый по данному платежу, потому что открытым
|
|
|
|
|
может быть только один за раз, если существует, отдаем действующий
|
|
|
|
|
|
2024-08-27 06:44:58 +00:00
|
|
|
|
(реализации на данный момент нет) Передача uniqID на создании\статусе диспута дает возможность проверять наличие
|
|
|
|
|
диспута (через опрос статуса) до этапа создания с внешнего вызова
|
|
|
|
|
|
2024-08-26 12:31:48 +00:00
|
|
|
|
При ошибках сервис кидает:
|
|
|
|
|
|
|
|
|
|
- `5хх`, если это отказ внешних шлюзов
|
|
|
|
|
- `404`, если это отсутствие данных
|
|
|
|
|
- `400`, если это ошибка в данных запросов
|
|
|
|
|
- `401`, если это отсутствие прав для доступа к `API`
|
|
|
|
|
|
|
|
|
|
При опросе диспута существует несколько значений параметра `ErrorReason`, при которых информация об диспуте не отдается
|
|
|
|
|
и наружу выкидывается `404`. Такое поведение возникнет, если в другом потоке `шедулатора` при обработке диспута возникли
|
|
|
|
|
ошибки\отказ внешних шлюзов с ключевыми данными и в рамках данного диспута проблема является непреодолимой. Единственным
|
|
|
|
|
способом решить данную проблему будет создание нового диспута.
|
|
|
|
|
|
|
|
|
|
## Модуль Schedule
|
|
|
|
|
|
|
|
|
|
Модуль с `шедулаторами`, которые по расписанию обрабатывают диспуты.
|
|
|
|
|
Все процессы в `шедулаторах` проходят в изоляциях транзакций, при исключениях возникает откат.
|
|
|
|
|
|
|
|
|
|
При обработке диспутов `шедулатор` блочит используемые айдишники на уровне запроса к базе.
|
|
|
|
|
Диспут у провайдера не будет создан, пока платеж находится в не финальном статусе, это ограничение на уровне `hellgate`.
|
|
|
|
|
Когда статус платежа
|
|
|
|
|
становится `captured|cancelled|failed` разрешена дальнейшая обработка диспута.
|
|
|
|
|
|
2024-08-30 09:21:38 +00:00
|
|
|
|
Если при финальном статусе платежа `captured` создавать на провайдере диспут является не желательной ситуацией, можно
|
|
|
|
|
установить опцию в терминале `DISPUTE_FLOW_CAPTURED_BLOCKED` и пулять
|
2024-08-26 12:31:48 +00:00
|
|
|
|
состояние
|
2024-10-29 10:49:03 +00:00
|
|
|
|
в топик\тг-провайдер-бот\filebeat на ручной разбор (`AdminManagement` module)
|
2024-08-26 12:31:48 +00:00
|
|
|
|
|
2024-08-30 09:21:38 +00:00
|
|
|
|
Не все провайдеры на данный момент поддерживают работу с диспутами по `API`.
|
2024-08-26 12:31:48 +00:00
|
|
|
|
Предполагается такой способ действия при этой ситуации:
|
|
|
|
|
|
2024-08-30 09:21:38 +00:00
|
|
|
|
1) При наличии диспутов по `API` у провайдеров в терминале добавляется опция — `DISPUTE_FLOW_PROVIDERS_API_EXIST`
|
2024-08-26 12:31:48 +00:00
|
|
|
|
2) если эта опция терминала есть, то сервис ищет роут до адаптера и отправляет запрос по трифт протоколу, иначе будет
|
2024-08-30 09:21:38 +00:00
|
|
|
|
пулять в топик\тг-провайдер-бот\filebeat
|
|
|
|
|
3) если возникнет ошибка роута, то будет пулять в топик\тг-провайдер-бот\filebeat
|
2024-08-26 12:31:48 +00:00
|
|
|
|
|
|
|
|
|
Используется экспоненциальный пуллинг, после которого мы считаем, что диспут протух и поллить его не надо.
|
|
|
|
|
Опция `DISPUTE_FLOW_MAX_TIME_POLLING_MIN` контролирует максимальное время пуллинга
|
|
|
|
|
Диспуты на проверку статуса упорядочиваются по последнему времени проверки поля `next_check_after`, берутся самые
|
|
|
|
|
древние
|
|
|
|
|
|
|
|
|
|
Ответственность за актуальный статус диспута несет конкретный адаптер. Решение остается за адаптером, тк детали
|
|
|
|
|
реализации могут отличаться в зависимости от интеграции, `disputes-api` работает уже с результатом этого процесса и
|
|
|
|
|
занимается обновлением статуса диспута в своей БД. При этом, при создании диспута необходимо в адаптере по возможности
|
|
|
|
|
проверять наличие существующего диспута, в случае отказа внешних шлюзов после вызова ручки создания диспута на адаптере.
|
|
|
|
|
|
|
|
|
|
Если по какой то причине на этапе опроса статуса `шедулатор` не найдет в БД актуальную запись об
|
|
|
|
|
конкретном `provider_dispute_id` (т.е. диспут в адаптере не был создан), то обработка диспута будет возвращена на этап
|
|
|
|
|
назад, для попытки создать диспут в адаптере заново.
|
|
|
|
|
|
|
|
|
|
Перед созданием корректировки сервис пытается найти уже созданные корректировки и найти среди них существующую
|
|
|
|
|
корректировку и при успехе переводит диспут в успех. Этот процесс ликвидирует ситуацию дублей корректировок.
|
|
|
|
|
В идеале, после создания корректировки диспут переводится в успех.
|
|
|
|
|
|
|
|
|
|
# Консистентность
|
|
|
|
|
|
|
|
|
|
Данная реализация предусматривает, что сервис при обработке не зависнет в неопределенном состоянии, а если это
|
|
|
|
|
произойдет, то это не повлияет на состояние данных
|
|
|
|
|
|
|
|
|
|
Критичные внешние шлююзы:
|
|
|
|
|
|
|
|
|
|
- `postgres` [RW] (хранение данных по диспутам)
|
|
|
|
|
- `hellgate` [RW] (запись корректировок)
|
|
|
|
|
- `file-storage-v2` [RW] (хранение файлов чеков диспутов)
|
|
|
|
|
- `dominant` [R] `bouncer` [R] `token-keeper-v2` [R] (авторизация по токену)
|
|
|
|
|
|
|
|
|
|
В модуле `API` при падении внешних узлов в общей цепочке вызовов будет откат транзакции, данные в БД не запишутся,
|
|
|
|
|
диспут не будет создан и наружу вернется выбранный http-код
|
|
|
|
|
|
|
|
|
|
В модуле `Schedule` при падении внешних узлов в общей цепочке вызовов будет откат транзакции, данные в БД не запишутся,
|
|
|
|
|
а также продусмотрена проверка `hellgate` , существует ли уже такая корректировка
|
|
|
|
|
|
|
|
|
|
Запись `file-storage-v2` не регулируется на уровня транзакции сервиса, но конкретно в случае `file-storage-v2`
|
|
|
|
|
возможность повторной записи не является критичным фактором
|
|
|
|
|
|
|
|
|
|
Вызов адаптеров — пулинг на падения не влияет, но при создании предполагается, что это ответственность адаптера
|
|
|
|
|
удостовериться, что такого диспута еще не существует.
|
2024-08-30 13:03:39 +00:00
|
|
|
|
|
|
|
|
|
# Модуль ручного разбора
|
|
|
|
|
|
|
|
|
|
схема такая:
|
|
|
|
|
после создания диспута через нашу внешнюю апишку, будет происходить несколько кейсов:
|
|
|
|
|
|
|
|
|
|
- если `CreatedDisputesService` при попытке создать диспут в провайдере понимает, что такой ручки в провайдере не
|
|
|
|
|
существут, отправляет на ручной разбор
|
|
|
|
|
- если не выставлен флаг в опциях `DISPUTE_FLOW_PROVIDERS_API_EXIST` , то тоже отправляет на ручной разбор
|
|
|
|
|
- если это captured платеж и выставлена опция `DISPUTE_FLOW_CAPTURED_BLOCKED` , то тоже отправляет на ручной разбор
|
|
|
|
|
|
|
|
|
|
Далее, через внутрений трифт-интерфейс саппорт получает способ манипулировать диспутом для его
|
2024-10-29 10:49:03 +00:00
|
|
|
|
обработки (`AdminManagementDisputesService`)
|
2024-08-30 13:03:39 +00:00
|
|
|
|
|
|
|
|
|
- Перед переводом диспута в финальный статус саппорт должен будет забиндить айди созданного диспута в провайдере через
|
|
|
|
|
ручку `BindCreated()`. Здесь особенность, что этот метод фильтрует возможность биндить диспуты только созданные
|
2024-09-19 14:09:35 +00:00
|
|
|
|
вручную (из `manual_created`)
|
2024-08-30 13:03:39 +00:00
|
|
|
|
|
|
|
|
|
Далее, в режиме ручного разбора есть опция финализации диспута в фейл (`CancelPending()`) либо в
|
|
|
|
|
успех (`ApprovePending()`). Здесь особенность, что в фейл можно перевести любой диспут имеющий не финальный статус, а в
|
|
|
|
|
успех можно перевести, только если гарантировано создан внешний диспут у провайдера (
|
2024-09-19 14:09:35 +00:00
|
|
|
|
из `pending`,`manual_pending`)
|
2024-08-30 13:03:39 +00:00
|
|
|
|
|
|
|
|
|
- Из за того, что для ручных диспутов добавлены отдельные
|
2024-09-19 14:09:35 +00:00
|
|
|
|
статусы `manual_pending` ,`manual_created` не происходит ситуации, что такие диспуты попадут в
|
2024-08-30 13:03:39 +00:00
|
|
|
|
таску `PendingDisputesService` которая автоматически вызывает апи провайдера для проверки статуса
|
|
|
|
|
|
|
|
|
|
# Схема аппрува корректировок
|
|
|
|
|
|
|
|
|
|
Добавить в БД для диспута колонку "IS_AUTO", по дефолту проставляем туда FALSE.
|
|
|
|
|
Получаем успешный статус от провайдера, пишем в БД статус READY_FOR_ADJUSTMENT.
|
|
|
|
|
Корректировки проводим в отдельном потоке по расписанию, как сейчас создаем и проводим диспуты (просто последний вариант
|
|
|
|
|
разбиваем на два отдельных). По расписанию стартует поток и автоматически проводит только те проводки, где IS_AUTO =
|
|
|
|
|
TRUE. В идеале саппорт/фины будут скриптом/в админке сначала проставлять TRUE.
|