419 lines
8.8 KiB
Markdown
419 lines
8.8 KiB
Markdown
# YooKassa Mock v2
|
||
|
||
Легковесный mock-сервер для эмуляции базового сценария работы YooKassa.
|
||
|
||
## Что умеет
|
||
|
||
- создавать платеж
|
||
- возвращать `confirmation_url`
|
||
- показывать checkout-страницу
|
||
- завершать платеж как:
|
||
- `succeeded`
|
||
- `canceled`
|
||
- отправлять webhook
|
||
- повторять webhook при ошибке
|
||
- поддерживать `Idempotence-Key`
|
||
- отдавать статус платежа по `payment_id`
|
||
|
||
---
|
||
|
||
# Файлы
|
||
|
||
- `main.py` — FastAPI приложение
|
||
- `requirements.txt` — зависимости
|
||
- `Dockerfile` — образ
|
||
- `docker-compose.yml` — запуск контейнера
|
||
- `.env` — переменные окружения
|
||
|
||
---
|
||
|
||
# Запуск
|
||
|
||
## 1. Сборка и старт
|
||
|
||
~~~bash
|
||
docker compose up -d --build
|
||
~~~
|
||
|
||
## 2. Проверка здоровья
|
||
|
||
~~~bash
|
||
curl -s http://127.0.0.1:${YMK_PUBLIC_PORT}/health
|
||
~~~
|
||
|
||
Пример ответа:
|
||
|
||
~~~json
|
||
{"status":"ok","payments_total":0,"idempotence_keys_total":0}
|
||
~~~
|
||
|
||
---
|
||
|
||
# Переменные окружения
|
||
|
||
Пример `.env`:
|
||
|
||
~~~env
|
||
YMK_PUBLIC_PORT=8083
|
||
|
||
WEBHOOK_URL=http://192.168.149.101:8000/api/tickets/webhook/yookassa
|
||
|
||
MOCK_HOST=192.168.149.101
|
||
MOCK_PORT=8083
|
||
|
||
MOCK_REQUIRE_AUTH=0
|
||
MOCK_SHOP_ID=test_shop
|
||
MOCK_SECRET_KEY=test_secret
|
||
|
||
WEBHOOK_RETRY_COUNT=3
|
||
WEBHOOK_RETRY_DELAY_SEC=1
|
||
WEBHOOK_DELAY_SEC=0
|
||
~~~
|
||
|
||
## Описание
|
||
|
||
### `YMK_PUBLIC_PORT`
|
||
Внешний порт хоста, на который публикуется контейнер.
|
||
|
||
### `WEBHOOK_URL`
|
||
URL для отправки webhook после смены статуса платежа.
|
||
|
||
### `MOCK_HOST`
|
||
Хост, который будет подставляться в `confirmation_url`.
|
||
|
||
### `MOCK_PORT`
|
||
Порт, который будет подставляться в `confirmation_url`.
|
||
|
||
### `MOCK_REQUIRE_AUTH`
|
||
- `0` — Basic Auth не обязателен
|
||
- `1` — Basic Auth обязателен
|
||
|
||
### `MOCK_SHOP_ID`
|
||
Логин для Basic Auth, если auth включен.
|
||
|
||
### `MOCK_SECRET_KEY`
|
||
Пароль для Basic Auth, если auth включен.
|
||
|
||
### `WEBHOOK_RETRY_COUNT`
|
||
Количество попыток отправки webhook.
|
||
|
||
### `WEBHOOK_RETRY_DELAY_SEC`
|
||
Пауза между retry webhook.
|
||
|
||
### `WEBHOOK_DELAY_SEC`
|
||
Искусственная задержка перед первой отправкой webhook.
|
||
|
||
---
|
||
|
||
# API
|
||
|
||
## 1. POST `/v3/payments`
|
||
|
||
Создание платежа.
|
||
|
||
### Обязательное
|
||
- заголовок `Idempotence-Key`
|
||
- `confirmation.return_url`
|
||
- `amount.value`
|
||
|
||
### Пример запроса
|
||
|
||
~~~bash
|
||
curl -s -X POST http://127.0.0.1:8083/v3/payments \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Idempotence-Key: test-001' \
|
||
-d '{
|
||
"amount": {
|
||
"value": "100.00",
|
||
"currency": "RUB"
|
||
},
|
||
"confirmation": {
|
||
"type": "redirect",
|
||
"return_url": "http://192.168.149.101:3000/payment/return"
|
||
},
|
||
"capture": true,
|
||
"description": "Заказ №1"
|
||
}'
|
||
~~~
|
||
|
||
### Пример успешного ответа
|
||
|
||
~~~json
|
||
{
|
||
"id": "fdb332f8-bb1d-4def-bc1d-d5b00a7e287a",
|
||
"status": "pending",
|
||
"paid": false,
|
||
"amount": {
|
||
"value": "100.00",
|
||
"currency": "RUB"
|
||
},
|
||
"confirmation": {
|
||
"type": "redirect",
|
||
"confirmation_url": "http://192.168.149.101:8083/checkout?payment_id=fdb332f8-bb1d-4def-bc1d-d5b00a7e287a"
|
||
},
|
||
"created_at": "2026-03-12T06:35:47.512Z",
|
||
"description": "Заказ №1",
|
||
"metadata": {},
|
||
"capture": true,
|
||
"recipient": {
|
||
"account_id": "test_shop",
|
||
"gateway_id": "100700"
|
||
},
|
||
"refundable": false,
|
||
"test": true
|
||
}
|
||
~~~
|
||
|
||
### Идемпотентность
|
||
|
||
Если повторно вызвать `POST /v3/payments` с тем же `Idempotence-Key`, мок вернет тот же платеж, а не создаст новый.
|
||
|
||
---
|
||
|
||
## 2. GET `/v3/payments/{payment_id}`
|
||
|
||
Получение статуса платежа.
|
||
|
||
### Пример
|
||
|
||
~~~bash
|
||
curl -s http://127.0.0.1:8083/v3/payments/fdb332f8-bb1d-4def-bc1d-d5b00a7e287a
|
||
~~~
|
||
|
||
### Пример ответа
|
||
|
||
~~~json
|
||
{
|
||
"id": "fdb332f8-bb1d-4def-bc1d-d5b00a7e287a",
|
||
"status": "succeeded",
|
||
"paid": true,
|
||
"amount": {
|
||
"value": "100.00",
|
||
"currency": "RUB"
|
||
},
|
||
"confirmation": {
|
||
"type": "redirect",
|
||
"confirmation_url": "http://192.168.149.101:8083/checkout?payment_id=fdb332f8-bb1d-4def-bc1d-d5b00a7e287a"
|
||
},
|
||
"created_at": "2026-03-12T06:35:47.512Z",
|
||
"description": "Заказ №1",
|
||
"metadata": {},
|
||
"capture": true,
|
||
"recipient": {
|
||
"account_id": "test_shop",
|
||
"gateway_id": "100700"
|
||
},
|
||
"refundable": true,
|
||
"test": true
|
||
}
|
||
~~~
|
||
|
||
---
|
||
|
||
## 3. GET `/checkout?payment_id=<id>`
|
||
|
||
HTML-страница оплаты.
|
||
|
||
Что показывает:
|
||
- `payment_id`
|
||
- статус
|
||
- сценарий
|
||
- описание
|
||
- сумму
|
||
|
||
На странице есть три кнопки:
|
||
- `Оплатить успешно`
|
||
- `Отменить оплату`
|
||
- `Ошибка оплаты`
|
||
|
||
---
|
||
|
||
## 4. POST `/process/{payment_id}`
|
||
|
||
Меняет статус платежа, отправляет webhook, делает redirect на `return_url`.
|
||
|
||
### Входные варианты
|
||
|
||
Через form-data / x-www-form-urlencoded поле `action`:
|
||
|
||
- `success`
|
||
- `cancel`
|
||
- `fail`
|
||
|
||
### Пример success
|
||
|
||
~~~bash
|
||
curl -i -X POST http://127.0.0.1:8083/process/fdb332f8-bb1d-4def-bc1d-d5b00a7e287a \
|
||
-d 'action=success'
|
||
~~~
|
||
|
||
### Пример cancel
|
||
|
||
~~~bash
|
||
curl -i -X POST http://127.0.0.1:8083/process/294ec8cd-c1fb-44b4-91cc-04d669343390 \
|
||
-d 'action=cancel'
|
||
~~~
|
||
|
||
### Поведение
|
||
|
||
- `success` → статус `succeeded`, `paid=true`
|
||
- `cancel` → статус `canceled`, `paid=false`
|
||
- `fail` → статус `canceled`, `paid=false`
|
||
|
||
После этого сервис делает:
|
||
|
||
- webhook на `WEBHOOK_URL`
|
||
- `303 See Other` на `return_url`
|
||
|
||
---
|
||
|
||
## 5. GET `/health`
|
||
|
||
Проверка состояния сервиса.
|
||
|
||
### Пример
|
||
|
||
~~~bash
|
||
curl -s http://127.0.0.1:8083/health
|
||
~~~
|
||
|
||
### Ответ
|
||
|
||
~~~json
|
||
{
|
||
"status": "ok",
|
||
"payments_total": 2,
|
||
"idempotence_keys_total": 2
|
||
}
|
||
~~~
|
||
|
||
---
|
||
|
||
# Webhook
|
||
|
||
После `success`:
|
||
|
||
~~~json
|
||
{
|
||
"event": "payment.succeeded",
|
||
"type": "notification",
|
||
"object": {
|
||
"id": "payment_id",
|
||
"status": "succeeded",
|
||
"paid": true,
|
||
"amount": {
|
||
"value": "100.00",
|
||
"currency": "RUB"
|
||
},
|
||
"description": "Заказ №1",
|
||
"metadata": {}
|
||
}
|
||
}
|
||
~~~
|
||
|
||
После `cancel` / `fail`:
|
||
|
||
~~~json
|
||
{
|
||
"event": "payment.canceled",
|
||
"type": "notification",
|
||
"object": {
|
||
"id": "payment_id",
|
||
"status": "canceled",
|
||
"paid": false,
|
||
"amount": {
|
||
"value": "250.00",
|
||
"currency": "RUB"
|
||
},
|
||
"description": "Заказ №2",
|
||
"metadata": {
|
||
"mock_scenario": "cancel"
|
||
}
|
||
}
|
||
}
|
||
~~~
|
||
|
||
---
|
||
|
||
# Retry webhook
|
||
|
||
Если endpoint webhook отвечает ошибкой или недоступен:
|
||
|
||
- мок делает повторные попытки
|
||
- количество попыток задается `WEBHOOK_RETRY_COUNT`
|
||
- задержка между попытками задается `WEBHOOK_RETRY_DELAY_SEC`
|
||
|
||
Логи смотреть так:
|
||
|
||
~~~bash
|
||
docker logs --tail 100 yookassa-mock
|
||
~~~
|
||
|
||
---
|
||
|
||
# Сценарии через metadata
|
||
|
||
При создании платежа можно задать сценарий по умолчанию:
|
||
|
||
~~~json
|
||
"metadata": {
|
||
"mock_scenario": "cancel"
|
||
}
|
||
~~~
|
||
|
||
Допустимые значения:
|
||
- `success`
|
||
- `cancel`
|
||
- `fail`
|
||
|
||
Если в `POST /process/{payment_id}` не передать `action`, будет использован `mock_scenario`.
|
||
|
||
---
|
||
|
||
# Basic Auth
|
||
|
||
Если включить:
|
||
|
||
~~~env
|
||
MOCK_REQUIRE_AUTH=1
|
||
~~~
|
||
|
||
Тогда endpoints `/v3/payments` и `/v3/payments/{payment_id}` будут требовать Basic Auth.
|
||
|
||
Логин/пароль берутся из:
|
||
- `MOCK_SHOP_ID`
|
||
- `MOCK_SECRET_KEY`
|
||
|
||
---
|
||
|
||
# Ограничения
|
||
|
||
Это мок, не полная копия YooKassa.
|
||
|
||
Сейчас нет:
|
||
- persistent storage
|
||
- списка платежей
|
||
- ручного cancel endpoint в стиле реального API
|
||
- полной схемы YooKassa
|
||
- реальной проверки секретов YooKassa
|
||
- capture/authorize flow с отдельным подтверждением списания
|
||
- рефандов
|
||
|
||
---
|
||
|
||
# Текущее состояние проверки
|
||
|
||
Проверено вручную:
|
||
|
||
- создание платежа — OK
|
||
- `confirmation_url` — OK
|
||
- `GET /v3/payments/{id}` — OK
|
||
- идемпотентность — OK
|
||
- `pending -> succeeded` — OK
|
||
- `pending -> canceled` — OK
|
||
- redirect на `return_url` — OK
|
||
- retry webhook — OK
|
||
|
||
Проблема сейчас только одна:
|
||
`WEBHOOK_URL` отвечает `404 Not Found`, значит endpoint на основном backend отсутствует или указан неверно.
|