Нужно дописать Rails-приложение для переводов денег между пользователями, с автоматической конвертацией валют.
В приложении две модели:
User
(может посылать и принимать переводы), с такими аттрибутами:balance_cents
: баланс в центахbalance_currency
: валюта баланса (ARS
|BRL
|MXN
)pending_balance_cents
: баланс с учетом неокончившихся переводов.external_id
: ID пользователя во внешнем сервисе (об этом ниже)
Transfer
(перевод), с аттрибутами:sender_id
: ID отправителя (User
)receiver_id
: ID получателя (User
)amount_cents
: размер перевода (в валюте отправителя)rate
: курс обмена (в валюту получателя)external_id
: ID перевода во внешнем сервисеstatus
:pending
: перевод создан и отправлен во внешний сервисsucceeded
: перевод завершился успешноfailed
: перевод завершился с ошибкой (т.е. фактически перевода не произошло)
Есть внешний сервис (т.е. мы отправляем туда HTTP-запросы):
Gateway
(lib/gateway.rb
):.create_transfer(from_id:, to_id:, amount_cents:)
:- создает перевод во внешнем сервисе, где
from_id
иto_id
–external_id
юзеров - возращает:
transfer_id
– ID созданного трансфера во внешнем сервисеrate
- рейт, по которому происходит конвертация между валютой отправителя и валютой получателя
- через некоторое время после запроса отправляет вебхук со статусом перевода (
succeeded
илиfailed
)
Есть 2 контроллера:
TransfersController
:- Вызывается пользователями сервиса для отправки переводов
- Принимает параметры:
to_id
– ID юзера, которому делаем переводamount_cents
– Сумма перевода в центах (считаем, что в валюте отправителя)
- В контроллере есть аутентификация, поэтому можем обращаться к
current_user
(который будет отправителем перевода)
WebhooksController
:- Принимает вебхуки о статусах переводов от
Gateway
- Параметры:
transfer_id
– ID перевода в gateway (нашexternal_id
)status
– статус перевода (succeeded
илиfailed
)
- Принимает вебхуки о статусах переводов от
- Заимплементить контроллеры с условиями:
TransfersController
:Transfer
не может быть создан, если баланс отправителя меньше суммы в запросе (подсказка: для этого можно использоватьpending_balance_cents
)- Нужно создать трансфер во внешнем сервисе
Gateway
- Нужно создать
Transfer
в базе со статусомpending
,external_id
иrate
из предыдущего пункта - Если на каком-то из шагов произошла ошибка, нужно вернуть статус
400
с текстом этой ошибки
WebhooksController
:- Нужно обработать статус трансфера и в зависимости от него обновить балансы пользователей (учитывая
rate
) - Если мы вынуждены по какой-либо причине упасть, и хотим, чтобы вебхук пришел еше раз, нужно вернуть статус
400
- Нужно обработать статус трансфера и в зависимости от него обновить балансы пользователей (учитывая
- Нужно учитывать, что сервис – высоконагруженный, то есть одновременно приходит много запросов
- Баланс пользователей не может опускаться ниже нуля ни при каких условиях
- Важно не только написать "работающий" production-ready код, но и удобно его организовать: можно писать сервисы, использовать гемы (допустим, есть все, какие нужно) и тд.
app/controllers/v1/transfers_controller.rb
– эндпойнт создания трансферовapp/controllers/webhooks_controller.rb
– сюда приходят вебхукиapp/models/transfer.rb
– трансферapp/models/user.rb
- юзерlib/gateway.rb
– клиент, общающийся с внешним сервисом