Files
remnawave-bedolaga-telegram…/tests/services/test_pal24_service_adapter.py
T
Fringg eb18994b7d fix: complete datetime.utcnow() → datetime.now(UTC) migration
- Migrate 660+ datetime.utcnow() across 153 files to datetime.now(UTC)
- Migrate 30+ datetime.now() without UTC to datetime.now(UTC)
- Convert all 170 DateTime columns to DateTime(timezone=True)
- Add migrate_datetime_to_timestamptz() in universal_migration with SET LOCAL timezone='UTC' safety
- Remove 70+ .replace(tzinfo=None) workarounds
- Fix utcfromtimestamp → fromtimestamp(..., tz=UTC)
- Fix fromtimestamp() without tz= (system_logs, backup_service, referral_diagnostics)
- Fix fromisoformat/isoparse to ensure aware output (platega, yookassa, wata, miniapp, nalogo)
- Fix strptime() to add .replace(tzinfo=UTC) (backup_service, referral_diagnostics)
- Fix datetime.combine() to include tzinfo=UTC (remnawave_sync, traffic_monitoring)
- Fix datetime.max/datetime.min sentinels with .replace(tzinfo=UTC)
- Rename panel_datetime_to_naive_utc → panel_datetime_to_utc
- Remove DTZ003 from ruff ignore list
2026-02-17 04:45:40 +03:00

138 lines
4.5 KiB
Python

"""Тесты Pal24Service и вспомогательных функций."""
from __future__ import annotations
import sys
from datetime import UTC, datetime, timedelta
from decimal import Decimal
from pathlib import Path
from typing import Any
import pytest
ROOT_DIR = Path(__file__).resolve().parents[2]
if str(ROOT_DIR) not in sys.path:
sys.path.insert(0, str(ROOT_DIR))
from app.config import settings
from app.external.pal24_client import Pal24APIError, Pal24Client
from app.services.pal24_service import Pal24Service
class StubPal24Client:
def __init__(self, configured: bool = True, response: dict[str, Any] | None = None) -> None:
self.is_configured = configured
self.response = response or {
'success': True,
'bill_id': 'BILL42',
'status': 'NEW',
'transfer_url': 'https://pal24/sbp',
'link_url': 'https://pal24/card',
'currency': 'RUB',
}
self.calls: list[dict[str, Any]] = []
async def create_bill(self, **kwargs: Any) -> dict[str, Any]:
self.calls.append(kwargs)
return self.response
async def get_bill_status(self, bill_id: str) -> dict[str, Any]:
return {'id': bill_id, 'status': 'NEW'}
async def get_payment_status(self, payment_id: str) -> dict[str, Any]:
return {'id': payment_id, 'status': 'SUCCESS'}
async def get_bill_payments(self, bill_id: str) -> dict[str, Any]:
return {'id': bill_id, 'payments': [{'id': 'PAY-1'}]}
def _enable_pal24(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(type(settings), 'is_pal24_enabled', lambda self: True, raising=False)
monkeypatch.setattr(settings, 'PAL24_SHOP_ID', 'shop42', raising=False)
monkeypatch.setattr(settings, 'PAL24_SIGNATURE_TOKEN', 'sigsecret', raising=False)
@pytest.fixture
def anyio_backend() -> str:
return 'asyncio'
@pytest.mark.anyio('asyncio')
async def test_create_bill_success(monkeypatch: pytest.MonkeyPatch) -> None:
_enable_pal24(monkeypatch)
client = StubPal24Client()
service = Pal24Service(client)
monkeypatch.setattr(Pal24Client, 'normalize_amount', staticmethod(lambda amount: Decimal('500.00')), raising=False)
result = await service.create_bill(
amount_kopeks=50000,
user_id=7,
order_id='order-7',
description='Пополнение',
ttl_seconds=600,
custom_payload={'extra': 'value'},
payer_email='user@example.com',
payment_method='BANK_CARD',
)
assert result['bill_id'] == 'BILL42'
assert client.calls and client.calls[0]['amount'] == Decimal('500.00')
assert client.calls[0]['shop_id'] == 'shop42'
assert client.calls[0]['description'] == 'Пополнение'
assert client.calls[0]['custom'] == {'extra': 'value'}
assert client.calls[0]['payment_method'] == 'BANK_CARD'
@pytest.mark.anyio('asyncio')
async def test_create_bill_requires_configuration(monkeypatch: pytest.MonkeyPatch) -> None:
_enable_pal24(monkeypatch)
client = StubPal24Client(configured=False)
service = Pal24Service(client)
with pytest.raises(Pal24APIError):
await service.create_bill(
amount_kopeks=1000,
user_id=1,
order_id='order',
description='desc',
)
@pytest.mark.anyio('asyncio')
async def test_get_bill_payments(monkeypatch: pytest.MonkeyPatch) -> None:
_enable_pal24(monkeypatch)
client = StubPal24Client()
service = Pal24Service(client)
result = await service.get_bill_payments('BILL42')
assert result == {'id': 'BILL42', 'payments': [{'id': 'PAY-1'}]}
def test_parse_callback_success(monkeypatch: pytest.MonkeyPatch) -> None:
_enable_pal24(monkeypatch)
sig = Pal24Client.calculate_signature('100.00', 'INV1', api_token='sigsecret')
payload = {
'InvId': 'INV1',
'OutSum': '100.00',
'Status': 'SUCCESS',
'SignatureValue': sig,
}
result = Pal24Service.parse_callback(payload)
assert result['InvId'] == 'INV1'
def test_parse_callback_missing_fields(monkeypatch: pytest.MonkeyPatch) -> None:
_enable_pal24(monkeypatch)
with pytest.raises(Pal24APIError):
Pal24Service.parse_callback({'InvId': '1'})
def test_convert_to_kopeks_and_expiration() -> None:
assert Pal24Service.convert_to_kopeks('10.50') == 1050
expiration = Pal24Service.get_expiration(60)
assert isinstance(expiration, datetime)
assert expiration - datetime.now(UTC) <= timedelta(seconds=61)