180 lines
5.2 KiB
Python
180 lines
5.2 KiB
Python
import asyncio
|
|
import json
|
|
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock
|
|
|
|
from bot.payment_providers import cryptopay, severpay, stars
|
|
|
|
|
|
class _FakeSession:
|
|
def __call__(self):
|
|
return self
|
|
|
|
async def __aenter__(self):
|
|
return self
|
|
|
|
async def __aexit__(self, exc_type, exc, tb):
|
|
return False
|
|
|
|
async def commit(self):
|
|
pass
|
|
|
|
async def rollback(self):
|
|
pass
|
|
|
|
|
|
class _FakeJsonRequest:
|
|
def __init__(self, payload):
|
|
self._payload = payload
|
|
|
|
async def json(self):
|
|
return self._payload
|
|
|
|
|
|
def test_cryptopay_duplicate_success_webhook_does_not_finalize_again(monkeypatch):
|
|
session = _FakeSession()
|
|
payment = SimpleNamespace(payment_id=77, status="succeeded")
|
|
update = SimpleNamespace(
|
|
payload=SimpleNamespace(
|
|
payload=json.dumps(
|
|
{
|
|
"user_id": "42",
|
|
"subscription_months": "0",
|
|
"payment_db_id": "77",
|
|
"sale_mode": "hwid_devices@standard",
|
|
}
|
|
),
|
|
invoice_id=9001,
|
|
amount=100,
|
|
asset="USDT",
|
|
)
|
|
)
|
|
app = {
|
|
"async_session_factory": session,
|
|
"bot": SimpleNamespace(),
|
|
"settings": SimpleNamespace(traffic_sale_mode=False, DEFAULT_CURRENCY_SYMBOL="RUB"),
|
|
"i18n": SimpleNamespace(),
|
|
"subscription_service": SimpleNamespace(),
|
|
"referral_service": SimpleNamespace(),
|
|
}
|
|
|
|
monkeypatch.setattr(
|
|
cryptopay.payment_dal,
|
|
"get_payment_by_db_id",
|
|
AsyncMock(return_value=payment),
|
|
)
|
|
monkeypatch.setattr(
|
|
cryptopay.payment_dal,
|
|
"update_provider_payment_and_status",
|
|
AsyncMock(side_effect=AssertionError("duplicate webhook must not update payment")),
|
|
)
|
|
monkeypatch.setattr(
|
|
cryptopay,
|
|
"finalize_successful_payment",
|
|
AsyncMock(side_effect=AssertionError("duplicate webhook must not finalize")),
|
|
)
|
|
|
|
service = SimpleNamespace(settings=SimpleNamespace(traffic_sale_mode=False))
|
|
asyncio.run(cryptopay.CryptoPayService._invoice_paid_handler(service, update, app))
|
|
|
|
|
|
def test_severpay_duplicate_success_webhook_does_not_finalize_again(monkeypatch):
|
|
session = _FakeSession()
|
|
payment = SimpleNamespace(
|
|
payment_id=88,
|
|
user_id=42,
|
|
status="succeeded",
|
|
sale_mode="hwid_devices@standard",
|
|
purchased_hwid_devices=3,
|
|
purchased_gb=None,
|
|
subscription_duration_months=None,
|
|
amount=150.0,
|
|
currency="RUB",
|
|
user=None,
|
|
)
|
|
|
|
async def lookup_payment(_session, *, order_id_raw=None, provider_payment_id=None):
|
|
assert _session is session
|
|
assert order_id_raw == "88"
|
|
assert provider_payment_id == "sev-1"
|
|
return payment
|
|
|
|
monkeypatch.setattr(severpay, "lookup_payment_by_order_or_provider_id", lookup_payment)
|
|
monkeypatch.setattr(
|
|
severpay.payment_dal,
|
|
"update_provider_payment_and_status",
|
|
AsyncMock(side_effect=AssertionError("duplicate webhook must not update payment")),
|
|
)
|
|
monkeypatch.setattr(
|
|
severpay,
|
|
"finalize_successful_payment",
|
|
AsyncMock(side_effect=AssertionError("duplicate webhook must not finalize")),
|
|
)
|
|
|
|
service = SimpleNamespace(
|
|
configured=True,
|
|
_validate_signature=lambda _payload: True,
|
|
async_session_factory=session,
|
|
settings=SimpleNamespace(traffic_sale_mode=False),
|
|
bot=SimpleNamespace(),
|
|
i18n=SimpleNamespace(),
|
|
subscription_service=SimpleNamespace(),
|
|
referral_service=SimpleNamespace(),
|
|
)
|
|
response = asyncio.run(
|
|
severpay.SeverPayService.webhook_route(
|
|
service,
|
|
_FakeJsonRequest(
|
|
{
|
|
"type": "payin",
|
|
"data": {
|
|
"id": "sev-1",
|
|
"order_id": "88",
|
|
"status": "success",
|
|
},
|
|
}
|
|
),
|
|
)
|
|
)
|
|
|
|
assert response.status == 200
|
|
|
|
|
|
def test_stars_duplicate_success_message_does_not_finalize_again(monkeypatch):
|
|
session = _FakeSession()
|
|
payment = SimpleNamespace(payment_id=99, status="succeeded")
|
|
message = SimpleNamespace(
|
|
successful_payment=SimpleNamespace(provider_payment_charge_id="stars-charge-1"),
|
|
from_user=SimpleNamespace(id=42),
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
stars.payment_dal,
|
|
"get_payment_by_db_id",
|
|
AsyncMock(return_value=payment),
|
|
)
|
|
monkeypatch.setattr(
|
|
stars.payment_dal,
|
|
"update_provider_payment_and_status",
|
|
AsyncMock(side_effect=AssertionError("duplicate stars payment must not update")),
|
|
)
|
|
monkeypatch.setattr(
|
|
stars,
|
|
"finalize_successful_payment",
|
|
AsyncMock(side_effect=AssertionError("duplicate stars payment must not finalize")),
|
|
)
|
|
|
|
service = SimpleNamespace()
|
|
asyncio.run(
|
|
stars.StarsService.process_successful_payment(
|
|
service,
|
|
session=session,
|
|
message=message,
|
|
payment_db_id=99,
|
|
months=3,
|
|
stars_amount=150,
|
|
i18n_data={},
|
|
sale_mode="hwid_devices@standard",
|
|
)
|
|
)
|