Initial commit: YooKassa mock v2

This commit is contained in:
adminko
2026-03-12 06:54:38 +00:00
commit c7db0a6dd1
7 changed files with 996 additions and 0 deletions

418
README.md Normal file
View File

@@ -0,0 +1,418 @@
# 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 отсутствует или указан неверно.