disputes-api/README.md

136 lines
13 KiB
Markdown
Raw Permalink Normal View History

# 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 на создании\статусе диспута дает возможность проверять наличие
диспута (через опрос статуса) до этапа создания с внешнего вызова
При ошибках сервис кидает:
- `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` и пулять
состояние
в топик\тг-провайдер-бот\filebeat на ручной разбор (`AdminManagement` module)
2024-08-30 09:21:38 +00:00
Не все провайдеры на данный момент поддерживают работу с диспутами по `API`.
Предполагается такой способ действия при этой ситуации:
2024-08-30 09:21:38 +00:00
1) При наличии диспутов по `API` у провайдеров в терминале добавляется опция — `DISPUTE_FLOW_PROVIDERS_API_EXIST`
2) если эта опция терминала есть, то сервис ищет роут до адаптера и отправляет запрос по трифт протоколу, иначе будет
2024-08-30 09:21:38 +00:00
пулять в топик\тг-провайдер-бот\filebeat
3) если возникнет ошибка роута, то будет пулять в топик\тг-провайдер-бот\filebeat
Используется экспоненциальный пуллинг, после которого мы считаем, что диспут протух и поллить его не надо.
Опция `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` , то тоже отправляет на ручной разбор
Далее, через внутрений трифт-интерфейс саппорт получает способ манипулировать диспутом для его
обработки (`AdminManagementDisputesService`)
2024-08-30 13:03:39 +00:00
- Перед переводом диспута в финальный статус саппорт должен будет забиндить айди созданного диспута в провайдере через
ручку `BindCreated()`. Здесь особенность, что этот метод фильтрует возможность биндить диспуты только созданные
вручную (из `manual_created`)
2024-08-30 13:03:39 +00:00
Далее, в режиме ручного разбора есть опция финализации диспута в фейл (`CancelPending()`) либо в
успех (`ApprovePending()`). Здесь особенность, что в фейл можно перевести любой диспут имеющий не финальный статус, а в
успех можно перевести, только если гарантировано создан внешний диспут у провайдера (
из `pending`,`manual_pending`)
2024-08-30 13:03:39 +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.