Добавлена отправка NotificationURL и SuccessURL
This commit is contained in:
@@ -20,6 +20,8 @@ class TBankAdapter:
|
|||||||
http_client: httpx.AsyncClient,
|
http_client: httpx.AsyncClient,
|
||||||
*,
|
*,
|
||||||
init_url: str,
|
init_url: str,
|
||||||
|
notification_url: str,
|
||||||
|
success_url: str,
|
||||||
terminal_key: str,
|
terminal_key: str,
|
||||||
password: str,
|
password: str,
|
||||||
timeout_seconds: float = 10.0,
|
timeout_seconds: float = 10.0,
|
||||||
@@ -29,6 +31,8 @@ class TBankAdapter:
|
|||||||
) -> None:
|
) -> None:
|
||||||
self._http_client = http_client
|
self._http_client = http_client
|
||||||
self._init_url = init_url
|
self._init_url = init_url
|
||||||
|
self._notification_url = notification_url
|
||||||
|
self._success_url = success_url
|
||||||
self._terminal_key = terminal_key
|
self._terminal_key = terminal_key
|
||||||
self._password = password
|
self._password = password
|
||||||
self._timeout_seconds = timeout_seconds
|
self._timeout_seconds = timeout_seconds
|
||||||
@@ -46,6 +50,8 @@ class TBankAdapter:
|
|||||||
return cls(
|
return cls(
|
||||||
http_client=http_client,
|
http_client=http_client,
|
||||||
init_url=config.init_url,
|
init_url=config.init_url,
|
||||||
|
notification_url=config.notification_url,
|
||||||
|
success_url=config.success_url,
|
||||||
terminal_key=config.auth.terminal_key,
|
terminal_key=config.auth.terminal_key,
|
||||||
password=config.auth.password,
|
password=config.auth.password,
|
||||||
timeout_seconds=config.timeout_seconds,
|
timeout_seconds=config.timeout_seconds,
|
||||||
@@ -116,6 +122,8 @@ class TBankAdapter:
|
|||||||
"TerminalKey": self._terminal_key,
|
"TerminalKey": self._terminal_key,
|
||||||
"Amount": amount_kopecks,
|
"Amount": amount_kopecks,
|
||||||
"OrderId": order_uuid,
|
"OrderId": order_uuid,
|
||||||
|
"NotificationURL": self._notification_url,
|
||||||
|
"SuccessURL": self._success_url,
|
||||||
}
|
}
|
||||||
payload["Token"] = _build_tbank_token(payload, password=self._password)
|
payload["Token"] = _build_tbank_token(payload, password=self._password)
|
||||||
return payload
|
return payload
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ class TBankPaymentAuthConfig(BaseModel):
|
|||||||
|
|
||||||
class TBankPaymentConfig(BaseModel):
|
class TBankPaymentConfig(BaseModel):
|
||||||
init_url: str = Field(..., min_length=1)
|
init_url: str = Field(..., min_length=1)
|
||||||
|
notification_url: str = Field(..., min_length=1)
|
||||||
|
success_url: str = Field(..., min_length=1)
|
||||||
auth: TBankPaymentAuthConfig
|
auth: TBankPaymentAuthConfig
|
||||||
timeout_seconds: float = Field(default=10.0, gt=0)
|
timeout_seconds: float = Field(default=10.0, gt=0)
|
||||||
retry_attempts: int = Field(default=2, ge=0)
|
retry_attempts: int = Field(default=2, ge=0)
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://merchant.example.com/tbank/notification"
|
||||||
|
success_url: "https://merchant.example.com/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "change-me-terminal-key"
|
terminal_key: "change-me-terminal-key"
|
||||||
password: "change-me-password"
|
password: "change-me-password"
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://merchant.test/tbank/notification"
|
||||||
|
success_url: "https://merchant.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "test-terminal-key"
|
terminal_key: "test-terminal-key"
|
||||||
password: "test-password"
|
password: "test-password"
|
||||||
|
|||||||
+3
-2
@@ -35,9 +35,10 @@
|
|||||||
| 026 | DONE | 2026-04-05 | Align CDEK order contract with single phone and kilogram package weight | `spec/tasks/026_align_cdek_order_contract_single_phone_and_weight_units.md` |
|
| 026 | DONE | 2026-04-05 | Align CDEK order contract with single phone and kilogram package weight | `spec/tasks/026_align_cdek_order_contract_single_phone_and_weight_units.md` |
|
||||||
| 027 | DONE | 2026-04-11 | Add TBank payment adapter, init_payment endpoint and rename order flow | `spec/tasks/027_add_tbank_payment_adapter_and_order_payment_link.md` |
|
| 027 | DONE | 2026-04-11 | Add TBank payment adapter, init_payment endpoint and rename order flow | `spec/tasks/027_add_tbank_payment_adapter_and_order_payment_link.md` |
|
||||||
| 028 | DONE | 2026-04-12 | Add PostgreSQL adapter, order repository and persist order after payment link creation | `spec/tasks/028_add_postgresql_order_persistence.md` |
|
| 028 | DONE | 2026-04-12 | Add PostgreSQL adapter, order repository and persist order after payment link creation | `spec/tasks/028_add_postgresql_order_persistence.md` |
|
||||||
|
| 029 | DONE | 2026-04-18 | Add TBank payment notification and success URLs | `spec/tasks/029_add_tbank_payment_urls.md` |
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
- Total: **29**
|
- Total: **30**
|
||||||
- TODO: **0**
|
- TODO: **0**
|
||||||
- DONE: **29**
|
- DONE: **30**
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
id: 029
|
||||||
|
title: Add TBank payment notification and success URLs
|
||||||
|
status: DONE
|
||||||
|
created: 2026-04-18
|
||||||
|
---
|
||||||
|
|
||||||
|
## Context
|
||||||
|
TBank Init API должен получать URLs для обработки webhook-уведомлений и возврата клиента после успешной оплаты. Сейчас `TBankAdapter` и секция `tbank_payment` не фиксируют передачу `NotificationURL` и `SuccessURL`.
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Добавить в конфигурацию TBank payment обязательные параметры `notification_url` и `success_url` и передавать их в payload инициализации платежа как `NotificationURL` и `SuccessURL`.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
- Изменения ограничены TBank payment config, TBank adapter payload mapping, wiring конфигурации и тестами.
|
||||||
|
- `NotificationURL` и `SuccessURL` MUST приходить из секции `tbank_payment` YAML-конфига.
|
||||||
|
- TBank adapter MUST продолжать инкапсулировать HTTP-взаимодействие, auth token, retries, timeout, serialization и error handling.
|
||||||
|
- Service и Controller MUST NOT содержать TBank-specific payload fields или provider HTTP-детали.
|
||||||
|
- Не изменять публичный request/response contract `POST /api/v1/delivery/init-payment`.
|
||||||
|
- Не изменять price flow, address suggestion flow, CDEK adapter и order repository.
|
||||||
|
- Не добавлять новые endpoints.
|
||||||
|
|
||||||
|
## Acceptance criteria
|
||||||
|
- `TBankPaymentConfig` содержит обязательные поля `notification_url: str` и `success_url: str`.
|
||||||
|
- Runtime YAML-конфиг и test YAML-конфиг содержат секцию `tbank_payment` с `notification_url` и `success_url`.
|
||||||
|
- `TBankAdapter` при вызове TBank Init API отправляет `NotificationURL` со значением `tbank_payment.notification_url`.
|
||||||
|
- `TBankAdapter` при вызове TBank Init API отправляет `SuccessURL` со значением `tbank_payment.success_url`.
|
||||||
|
- Auth token TBank формируется с учётом тех же полей payload, которые отправляются в Init API, включая `NotificationURL` и `SuccessURL`, если текущая реализация token generation строится по request payload.
|
||||||
|
- Отсутствие `notification_url` или `success_url` в YAML-конфиге приводит к детерминированной ошибке валидации конфигурации.
|
||||||
|
- `AggregatorService.init_payment()` продолжает вызывать `payment_adapter.create_payment_link(order_uuid, price)` без дополнительных URL-аргументов.
|
||||||
|
- Endpoint `POST /api/v1/delivery/init-payment` продолжает возвращать только `InitPaymentResponse(payment_url=...)`.
|
||||||
|
|
||||||
|
## Definition of Done
|
||||||
|
- [ ] В `app/config.py` добавлены поля `notification_url` и `success_url` в TBank payment config.
|
||||||
|
- [ ] YAML-конфиги обновлены новыми параметрами TBank payment.
|
||||||
|
- [ ] `TBankAdapter` передаёт `NotificationURL` и `SuccessURL` в payload TBank Init API.
|
||||||
|
- [ ] Token generation для TBank request остаётся корректной после добавления новых payload fields.
|
||||||
|
- [ ] Service и Controller не знают о `NotificationURL` и `SuccessURL`.
|
||||||
|
- [ ] Добавлены или обновлены тесты конфигурации.
|
||||||
|
- [ ] Добавлены или обновлены тесты TBank adapter payload.
|
||||||
|
- [ ] Все команды из раздела Commands проходят.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
- Обновить `tests/config/test_config_sections.py`: проверить обязательность `tbank_payment.notification_url` и `tbank_payment.success_url`.
|
||||||
|
- Обновить `tests/adapters/tbank/test_client.py`: проверить, что successful Init request payload содержит `NotificationURL` и `SuccessURL` из конфигурации.
|
||||||
|
- Обновить `tests/adapters/tbank/test_client.py`: проверить, что token generation остаётся детерминированной после добавления новых payload fields.
|
||||||
|
- При необходимости обновить `tests/smoke/test_app_import.py`, если smoke config требует новые обязательные поля.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
- `poetry run pytest tests/config/test_config_sections.py -q`
|
||||||
|
- `poetry run pytest tests/adapters/tbank/test_client.py -q`
|
||||||
|
- `poetry run pytest tests/smoke/test_app_import.py -q`
|
||||||
|
- `poetry run pytest -q`
|
||||||
|
- `python3 spec/gen_spec_index.py --check`
|
||||||
@@ -298,6 +298,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://merchant.test/tbank/notification"
|
||||||
|
success_url: "https://merchant.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "test-terminal-key"
|
terminal_key: "test-terminal-key"
|
||||||
password: "test-password"
|
password: "test-password"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from app.adapters.tbank.base import (
|
|||||||
TBankPaymentAdapterError,
|
TBankPaymentAdapterError,
|
||||||
TBankPaymentRequestError,
|
TBankPaymentRequestError,
|
||||||
)
|
)
|
||||||
|
from app.config import TBankPaymentAuthConfig, TBankPaymentConfig
|
||||||
|
|
||||||
|
|
||||||
class SequenceHTTPClient:
|
class SequenceHTTPClient:
|
||||||
@@ -48,6 +49,8 @@ class SequenceHTTPClient:
|
|||||||
def _make_adapter(
|
def _make_adapter(
|
||||||
http_client: SequenceHTTPClient,
|
http_client: SequenceHTTPClient,
|
||||||
*,
|
*,
|
||||||
|
notification_url: str = "https://example.test/tbank/notify",
|
||||||
|
success_url: str = "https://example.test/payment/success",
|
||||||
retry_attempts: int = 0,
|
retry_attempts: int = 0,
|
||||||
retry_backoff_seconds: float = 0.2,
|
retry_backoff_seconds: float = 0.2,
|
||||||
sleep_calls: list[float] | None = None,
|
sleep_calls: list[float] | None = None,
|
||||||
@@ -59,6 +62,8 @@ def _make_adapter(
|
|||||||
return TBankAdapter(
|
return TBankAdapter(
|
||||||
http_client=http_client, # type: ignore[arg-type]
|
http_client=http_client, # type: ignore[arg-type]
|
||||||
init_url="https://securepay.tinkoff.ru/v2/Init",
|
init_url="https://securepay.tinkoff.ru/v2/Init",
|
||||||
|
notification_url=notification_url,
|
||||||
|
success_url=success_url,
|
||||||
terminal_key="TBankTest",
|
terminal_key="TBankTest",
|
||||||
password="test-password",
|
password="test-password",
|
||||||
timeout_seconds=7.5,
|
timeout_seconds=7.5,
|
||||||
@@ -85,7 +90,14 @@ def test_create_payment_link_posts_signed_payload_and_maps_payment_url() -> None
|
|||||||
)
|
)
|
||||||
|
|
||||||
expected_token = hashlib.sha256(
|
expected_token = hashlib.sha256(
|
||||||
"125000order-uuid-1test-passwordTBankTest".encode("utf-8")
|
(
|
||||||
|
"125000"
|
||||||
|
"https://example.test/tbank/notify"
|
||||||
|
"order-uuid-1"
|
||||||
|
"test-password"
|
||||||
|
"https://example.test/payment/success"
|
||||||
|
"TBankTest"
|
||||||
|
).encode("utf-8")
|
||||||
).hexdigest()
|
).hexdigest()
|
||||||
assert result == "https://securepay.test/pay/1"
|
assert result == "https://securepay.test/pay/1"
|
||||||
assert http_client.calls == [
|
assert http_client.calls == [
|
||||||
@@ -96,6 +108,8 @@ def test_create_payment_link_posts_signed_payload_and_maps_payment_url() -> None
|
|||||||
"TerminalKey": "TBankTest",
|
"TerminalKey": "TBankTest",
|
||||||
"Amount": 125000,
|
"Amount": 125000,
|
||||||
"OrderId": "order-uuid-1",
|
"OrderId": "order-uuid-1",
|
||||||
|
"NotificationURL": "https://example.test/tbank/notify",
|
||||||
|
"SuccessURL": "https://example.test/payment/success",
|
||||||
"Token": expected_token,
|
"Token": expected_token,
|
||||||
},
|
},
|
||||||
"data": None,
|
"data": None,
|
||||||
@@ -108,6 +122,59 @@ def test_create_payment_link_posts_signed_payload_and_maps_payment_url() -> None
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_from_config_posts_configured_urls_and_deterministic_token() -> None:
|
||||||
|
response = httpx.Response(
|
||||||
|
200,
|
||||||
|
json={"Success": True, "PaymentURL": "https://securepay.test/pay/2"},
|
||||||
|
request=httpx.Request("POST", "https://securepay.tinkoff.ru/v2/Init"),
|
||||||
|
)
|
||||||
|
http_client = SequenceHTTPClient([response])
|
||||||
|
config = TBankPaymentConfig(
|
||||||
|
init_url="https://securepay.tinkoff.ru/v2/Init",
|
||||||
|
notification_url="https://merchant.test/tbank/notification",
|
||||||
|
success_url="https://merchant.test/payment/success",
|
||||||
|
auth=TBankPaymentAuthConfig(
|
||||||
|
terminal_key="ConfigTerminal",
|
||||||
|
password="config-password",
|
||||||
|
),
|
||||||
|
timeout_seconds=6.25,
|
||||||
|
retry_attempts=0,
|
||||||
|
retry_backoff_seconds=0.1,
|
||||||
|
)
|
||||||
|
adapter = TBankAdapter.from_config(
|
||||||
|
http_client=http_client, # type: ignore[arg-type]
|
||||||
|
config=config,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = asyncio.run(
|
||||||
|
adapter.create_payment_link(
|
||||||
|
order_uuid="order-uuid-2",
|
||||||
|
amount_kopecks=9900,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_token = hashlib.sha256(
|
||||||
|
(
|
||||||
|
"9900"
|
||||||
|
"https://merchant.test/tbank/notification"
|
||||||
|
"order-uuid-2"
|
||||||
|
"config-password"
|
||||||
|
"https://merchant.test/payment/success"
|
||||||
|
"ConfigTerminal"
|
||||||
|
).encode("utf-8")
|
||||||
|
).hexdigest()
|
||||||
|
assert result == "https://securepay.test/pay/2"
|
||||||
|
assert http_client.calls[0]["json"] == {
|
||||||
|
"TerminalKey": "ConfigTerminal",
|
||||||
|
"Amount": 9900,
|
||||||
|
"OrderId": "order-uuid-2",
|
||||||
|
"NotificationURL": "https://merchant.test/tbank/notification",
|
||||||
|
"SuccessURL": "https://merchant.test/payment/success",
|
||||||
|
"Token": expected_token,
|
||||||
|
}
|
||||||
|
assert http_client.calls[0]["timeout"] == 6.25
|
||||||
|
|
||||||
|
|
||||||
def test_create_payment_link_maps_4xx_to_request_error() -> None:
|
def test_create_payment_link_maps_4xx_to_request_error() -> None:
|
||||||
response = httpx.Response(
|
response = httpx.Response(
|
||||||
400,
|
400,
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://default.test/tbank/notification"
|
||||||
|
success_url: "https://default.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "yaml-terminal-key"
|
terminal_key: "yaml-terminal-key"
|
||||||
password: "yaml-password"
|
password: "yaml-password"
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://merchant.test/tbank/notification"
|
||||||
|
success_url: "https://merchant.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "test-terminal-key"
|
terminal_key: "test-terminal-key"
|
||||||
password: "test-password"
|
password: "test-password"
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ repository:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://merchant.test/tbank/notification"
|
||||||
|
success_url: "https://merchant.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "test-terminal-key"
|
terminal_key: "test-terminal-key"
|
||||||
password: "test-password"
|
password: "test-password"
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://merchant.test/tbank/notification"
|
||||||
|
success_url: "https://merchant.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "test-terminal-key"
|
terminal_key: "test-terminal-key"
|
||||||
password: "test-password"
|
password: "test-password"
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://merchant.test/tbank/notification"
|
||||||
|
success_url: "https://merchant.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "test-terminal-key"
|
terminal_key: "test-terminal-key"
|
||||||
password: "test-password"
|
password: "test-password"
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://merchant.test/tbank/notification"
|
||||||
|
success_url: "https://merchant.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "test-terminal-key"
|
terminal_key: "test-terminal-key"
|
||||||
password: "test-password"
|
password: "test-password"
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://merchant.test/tbank/notification"
|
||||||
|
success_url: "https://merchant.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "test-terminal-key"
|
terminal_key: "test-terminal-key"
|
||||||
password: "test-password"
|
password: "test-password"
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://override.test/tbank/notification"
|
||||||
|
success_url: "https://override.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "override-terminal-key"
|
terminal_key: "override-terminal-key"
|
||||||
password: "override-password"
|
password: "override-password"
|
||||||
|
|||||||
@@ -104,6 +104,56 @@ def _use_runtime_config_files(
|
|||||||
get_settings.cache_clear()
|
get_settings.cache_clear()
|
||||||
|
|
||||||
|
|
||||||
|
def _write_tbank_url_validation_config(
|
||||||
|
tmp_path: Path,
|
||||||
|
*,
|
||||||
|
include_notification_url: bool = True,
|
||||||
|
include_success_url: bool = True,
|
||||||
|
) -> Path:
|
||||||
|
notification_url = (
|
||||||
|
' notification_url: "https://merchant.test/tbank/notification"\n'
|
||||||
|
if include_notification_url
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
success_url = (
|
||||||
|
' success_url: "https://merchant.test/payment/success"\n'
|
||||||
|
if include_success_url
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
config_file = tmp_path / "config.yaml"
|
||||||
|
config_file.write_text(
|
||||||
|
f"""
|
||||||
|
controller: {{}}
|
||||||
|
|
||||||
|
service: {{}}
|
||||||
|
|
||||||
|
business_logic:
|
||||||
|
provider_price_multiplier: 1.0
|
||||||
|
|
||||||
|
repository: {{}}
|
||||||
|
|
||||||
|
adapter: {{}}
|
||||||
|
|
||||||
|
tbank_payment:
|
||||||
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
{notification_url}{success_url} auth:
|
||||||
|
terminal_key: "test-terminal-key"
|
||||||
|
password: "test-password"
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
dsn: "postgresql+asyncpg://postgres:postgres@localhost:5432/config_test"
|
||||||
|
|
||||||
|
address_suggestions: {{}}
|
||||||
|
|
||||||
|
observability:
|
||||||
|
service_name: "config-test"
|
||||||
|
otlp_endpoint: "http://collector:4317"
|
||||||
|
""".strip(),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
return config_file
|
||||||
|
|
||||||
|
|
||||||
def test_configuration_sections_are_loaded_from_yaml_file(
|
def test_configuration_sections_are_loaded_from_yaml_file(
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -127,6 +177,11 @@ def test_configuration_sections_are_loaded_from_yaml_file(
|
|||||||
assert settings.adapter.cdek_timeout_seconds == 10.0
|
assert settings.adapter.cdek_timeout_seconds == 10.0
|
||||||
assert settings.adapter.cdek_cache_ttl_seconds == 900
|
assert settings.adapter.cdek_cache_ttl_seconds == 900
|
||||||
assert settings.tbank_payment.init_url == "https://securepay.tinkoff.ru/v2/Init"
|
assert settings.tbank_payment.init_url == "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
assert (
|
||||||
|
settings.tbank_payment.notification_url
|
||||||
|
== "https://merchant.test/tbank/notification"
|
||||||
|
)
|
||||||
|
assert settings.tbank_payment.success_url == "https://merchant.test/payment/success"
|
||||||
assert settings.tbank_payment.auth.terminal_key == "test-terminal-key"
|
assert settings.tbank_payment.auth.terminal_key == "test-terminal-key"
|
||||||
assert settings.tbank_payment.auth.password == "test-password"
|
assert settings.tbank_payment.auth.password == "test-password"
|
||||||
assert settings.tbank_payment.timeout_seconds == 10.0
|
assert settings.tbank_payment.timeout_seconds == 10.0
|
||||||
@@ -203,6 +258,10 @@ def test_get_settings_returns_cached_instance(monkeypatch: pytest.MonkeyPatch) -
|
|||||||
assert first.service.provider_timeout_seconds == 10.0
|
assert first.service.provider_timeout_seconds == 10.0
|
||||||
assert first.business_logic.provider_price_multiplier == Decimal("1.0")
|
assert first.business_logic.provider_price_multiplier == Decimal("1.0")
|
||||||
assert first.tbank_payment.auth.terminal_key == "test-terminal-key"
|
assert first.tbank_payment.auth.terminal_key == "test-terminal-key"
|
||||||
|
assert (
|
||||||
|
first.tbank_payment.notification_url
|
||||||
|
== "https://merchant.test/tbank/notification"
|
||||||
|
)
|
||||||
assert first.postgres.dsn.endswith("/g2s_aggregator_test")
|
assert first.postgres.dsn.endswith("/g2s_aggregator_test")
|
||||||
assert first.address_suggestions.country_to_provider["RU"] == "dadata"
|
assert first.address_suggestions.country_to_provider["RU"] == "dadata"
|
||||||
assert first.observability.service_name == "g2s-aggregator-test"
|
assert first.observability.service_name == "g2s-aggregator-test"
|
||||||
@@ -226,6 +285,11 @@ def test_get_settings_uses_config_test_yaml_in_pytest_environment(
|
|||||||
assert settings.adapter.cdek_client_id == "test-id"
|
assert settings.adapter.cdek_client_id == "test-id"
|
||||||
assert settings.tbank_payment.auth.terminal_key == "override-terminal-key"
|
assert settings.tbank_payment.auth.terminal_key == "override-terminal-key"
|
||||||
assert settings.tbank_payment.auth.password == "override-password"
|
assert settings.tbank_payment.auth.password == "override-password"
|
||||||
|
assert (
|
||||||
|
settings.tbank_payment.notification_url
|
||||||
|
== "https://override.test/tbank/notification"
|
||||||
|
)
|
||||||
|
assert settings.tbank_payment.success_url == "https://override.test/payment/success"
|
||||||
assert settings.tbank_payment.timeout_seconds == 4.25
|
assert settings.tbank_payment.timeout_seconds == 4.25
|
||||||
assert settings.tbank_payment.retry_attempts == 1
|
assert settings.tbank_payment.retry_attempts == 1
|
||||||
assert settings.tbank_payment.retry_backoff_seconds == 0.05
|
assert settings.tbank_payment.retry_backoff_seconds == 0.05
|
||||||
@@ -283,6 +347,35 @@ def test_get_settings_fails_when_provider_price_multiplier_is_missing(
|
|||||||
get_settings.cache_clear()
|
get_settings.cache_clear()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("include_notification_url", "include_success_url", "expected_location"),
|
||||||
|
(
|
||||||
|
(False, True, ("tbank_payment", "notification_url")),
|
||||||
|
(True, False, ("tbank_payment", "success_url")),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_get_settings_fails_when_tbank_payment_url_is_missing(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
tmp_path: Path,
|
||||||
|
include_notification_url: bool,
|
||||||
|
include_success_url: bool,
|
||||||
|
expected_location: tuple[str, str],
|
||||||
|
) -> None:
|
||||||
|
config_file = _write_tbank_url_validation_config(
|
||||||
|
tmp_path,
|
||||||
|
include_notification_url=include_notification_url,
|
||||||
|
include_success_url=include_success_url,
|
||||||
|
)
|
||||||
|
_use_runtime_config_files(monkeypatch, test_config_file=config_file)
|
||||||
|
|
||||||
|
with pytest.raises(ValidationError) as error:
|
||||||
|
get_settings()
|
||||||
|
|
||||||
|
locations = {tuple(item["loc"]) for item in error.value.errors()}
|
||||||
|
assert expected_location in locations
|
||||||
|
get_settings.cache_clear()
|
||||||
|
|
||||||
|
|
||||||
def test_get_settings_fails_when_observability_section_is_missing(
|
def test_get_settings_fails_when_observability_section_is_missing(
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
@@ -181,6 +181,8 @@ adapter:
|
|||||||
|
|
||||||
tbank_payment:
|
tbank_payment:
|
||||||
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
init_url: "https://securepay.tinkoff.ru/v2/Init"
|
||||||
|
notification_url: "https://merchant.test/tbank/notification"
|
||||||
|
success_url: "https://merchant.test/payment/success"
|
||||||
auth:
|
auth:
|
||||||
terminal_key: "test-terminal-key"
|
terminal_key: "test-terminal-key"
|
||||||
password: "test-password"
|
password: "test-password"
|
||||||
|
|||||||
Reference in New Issue
Block a user