mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 03:40:26 +00:00
Display transaction numbers in admin payment list
This commit is contained in:
@@ -50,6 +50,8 @@ class StubHeleketService:
|
||||
self.info_response = info_response
|
||||
self.calls: list[Dict[str, Any]] = []
|
||||
self.info_calls: list[Dict[str, Optional[str]]] = []
|
||||
self.list_response: Optional[Dict[str, Any]] = None
|
||||
self.list_calls: list[Dict[str, Optional[str]]] = []
|
||||
|
||||
async def create_payment(self, payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
self.calls.append(payload)
|
||||
@@ -64,6 +66,18 @@ class StubHeleketService:
|
||||
self.info_calls.append({"uuid": uuid, "order_id": order_id})
|
||||
return self.info_response
|
||||
|
||||
async def list_payments(
|
||||
self,
|
||||
*,
|
||||
date_from: Optional[str] = None,
|
||||
date_to: Optional[str] = None,
|
||||
cursor: Optional[str] = None,
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
self.list_calls.append(
|
||||
{"date_from": date_from, "date_to": date_to, "cursor": cursor}
|
||||
)
|
||||
return self.list_response
|
||||
|
||||
|
||||
def _make_service(stub: Optional[StubHeleketService]) -> PaymentService:
|
||||
service = PaymentService.__new__(PaymentService) # type: ignore[call-arg]
|
||||
@@ -249,3 +263,53 @@ async def test_sync_heleket_payment_status_without_response(monkeypatch: pytest.
|
||||
|
||||
assert result is payment
|
||||
assert stub.info_calls == [{"uuid": payment.uuid, "order_id": payment.order_id}]
|
||||
assert stub.list_calls # fallback to history should be attempted
|
||||
|
||||
|
||||
@pytest.mark.anyio("asyncio")
|
||||
async def test_sync_heleket_payment_status_history_fallback(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
stub = StubHeleketService(response=None, info_response=None)
|
||||
stub.list_response = {
|
||||
"state": 0,
|
||||
"result": {
|
||||
"items": [
|
||||
{
|
||||
"uuid": "heleket-uuid",
|
||||
"order_id": "order-123",
|
||||
"status": "paid",
|
||||
"payment_amount": "150.00",
|
||||
}
|
||||
],
|
||||
"paginate": {"nextCursor": None},
|
||||
},
|
||||
}
|
||||
service = _make_service(stub)
|
||||
db = DummySession()
|
||||
|
||||
payment = SimpleNamespace(
|
||||
id=77,
|
||||
uuid="heleket-uuid",
|
||||
order_id="order-123",
|
||||
status="check",
|
||||
user_id=8,
|
||||
)
|
||||
|
||||
async def fake_get_by_id(db, payment_id):
|
||||
assert payment_id == payment.id
|
||||
return payment
|
||||
|
||||
captured: Dict[str, Any] = {}
|
||||
|
||||
async def fake_process(self, db, payload, *, metadata_key):
|
||||
captured["payload"] = payload
|
||||
captured["metadata_key"] = metadata_key
|
||||
return SimpleNamespace(**payload)
|
||||
|
||||
monkeypatch.setattr(heleket_crud, "get_heleket_payment_by_id", fake_get_by_id, raising=False)
|
||||
monkeypatch.setattr(PaymentService, "_process_heleket_payload", fake_process, raising=False)
|
||||
|
||||
result = await service.sync_heleket_payment_status(db, local_payment_id=payment.id)
|
||||
|
||||
assert result is not None
|
||||
assert captured["payload"]["status"] == "paid"
|
||||
assert stub.list_calls
|
||||
|
||||
@@ -4,6 +4,7 @@ from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -34,7 +35,12 @@ class DummyLocalPayment:
|
||||
|
||||
|
||||
class StubPal24Service:
|
||||
def __init__(self, *, configured: bool = True, response: Optional[Dict[str, Any]] = None) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
configured: bool = True,
|
||||
response: Optional[Dict[str, Any]] = None,
|
||||
) -> None:
|
||||
self.is_configured = configured
|
||||
self.response = response or {
|
||||
"success": True,
|
||||
@@ -45,6 +51,12 @@ class StubPal24Service:
|
||||
}
|
||||
self.calls: list[Dict[str, Any]] = []
|
||||
self.raise_error: Optional[Exception] = None
|
||||
self.status_response: Optional[Dict[str, Any]] = {"status": "NEW"}
|
||||
self.payment_status_response: Optional[Dict[str, Any]] = None
|
||||
self.bill_payments_response: Optional[Dict[str, Any]] = None
|
||||
self.status_calls: list[str] = []
|
||||
self.payment_status_calls: list[str] = []
|
||||
self.bill_payments_calls: list[str] = []
|
||||
|
||||
async def create_bill(self, **kwargs: Any) -> Dict[str, Any]:
|
||||
self.calls.append(kwargs)
|
||||
@@ -52,6 +64,18 @@ class StubPal24Service:
|
||||
raise self.raise_error
|
||||
return self.response
|
||||
|
||||
async def get_bill_status(self, bill_id: str) -> Optional[Dict[str, Any]]:
|
||||
self.status_calls.append(bill_id)
|
||||
return self.status_response
|
||||
|
||||
async def get_payment_status(self, payment_id: str) -> Optional[Dict[str, Any]]:
|
||||
self.payment_status_calls.append(payment_id)
|
||||
return self.payment_status_response
|
||||
|
||||
async def get_bill_payments(self, bill_id: str) -> Optional[Dict[str, Any]]:
|
||||
self.bill_payments_calls.append(bill_id)
|
||||
return self.bill_payments_response
|
||||
|
||||
|
||||
def _make_service(stub: Optional[StubPal24Service]) -> PaymentService:
|
||||
service = PaymentService.__new__(PaymentService) # type: ignore[call-arg]
|
||||
@@ -198,3 +222,110 @@ async def test_create_pal24_payment_handles_api_errors(monkeypatch: pytest.Monke
|
||||
language="ru",
|
||||
)
|
||||
assert result is None
|
||||
|
||||
|
||||
@pytest.mark.anyio("asyncio")
|
||||
async def test_get_pal24_payment_status_updates_from_remote(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
stub = StubPal24Service()
|
||||
stub.status_response = {"status": "SUCCESS"}
|
||||
stub.payment_status_response = {
|
||||
"success": True,
|
||||
"id": "PAY-1",
|
||||
"bill_id": "BILL-1",
|
||||
"status": "SUCCESS",
|
||||
"payment_method": "SBP",
|
||||
"account_amount": "700.00",
|
||||
"from_card": "676754******1234",
|
||||
}
|
||||
stub.bill_payments_response = {
|
||||
"data": [
|
||||
{
|
||||
"id": "PAY-1",
|
||||
"bill_id": "BILL-1",
|
||||
"status": "SUCCESS",
|
||||
"from_card": "676754******1234",
|
||||
"payment_method": "SBP",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
service = _make_service(stub)
|
||||
db = DummySession()
|
||||
|
||||
payment = SimpleNamespace(
|
||||
id=99,
|
||||
bill_id="BILL-1",
|
||||
payment_id=None,
|
||||
payment_status="NEW",
|
||||
payment_method=None,
|
||||
balance_amount=None,
|
||||
balance_currency=None,
|
||||
payer_account=None,
|
||||
status="NEW",
|
||||
is_paid=False,
|
||||
paid_at=None,
|
||||
transaction_id=None,
|
||||
user_id=1,
|
||||
)
|
||||
|
||||
async def fake_get_by_id(db: DummySession, payment_id: int) -> SimpleNamespace:
|
||||
assert payment_id == payment.id
|
||||
return payment
|
||||
|
||||
async def fake_update_status(
|
||||
db: DummySession,
|
||||
payment_obj: SimpleNamespace,
|
||||
*,
|
||||
status: str,
|
||||
**kwargs: Any,
|
||||
) -> SimpleNamespace:
|
||||
payment_obj.status = status
|
||||
payment_obj.last_status = status
|
||||
for key, value in kwargs.items():
|
||||
setattr(payment_obj, key, value)
|
||||
if "is_paid" in kwargs:
|
||||
payment_obj.is_paid = kwargs["is_paid"]
|
||||
await db.commit()
|
||||
return payment_obj
|
||||
|
||||
async def fake_finalize(
|
||||
self: PaymentService,
|
||||
db: DummySession,
|
||||
payment_obj: Any,
|
||||
*,
|
||||
payment_id: Optional[str] = None,
|
||||
trigger: str,
|
||||
) -> bool:
|
||||
return False
|
||||
|
||||
monkeypatch.setattr(
|
||||
payment_service_module,
|
||||
"get_pal24_payment_by_id",
|
||||
fake_get_by_id,
|
||||
raising=False,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
payment_service_module,
|
||||
"update_pal24_payment_status",
|
||||
fake_update_status,
|
||||
raising=False,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
PaymentService,
|
||||
"_finalize_pal24_payment",
|
||||
fake_finalize,
|
||||
raising=False,
|
||||
)
|
||||
|
||||
result = await service.get_pal24_payment_status(db, local_payment_id=payment.id)
|
||||
|
||||
assert result is not None
|
||||
assert payment.status == "SUCCESS"
|
||||
assert payment.payment_id == "PAY-1"
|
||||
assert payment.payment_status == "SUCCESS"
|
||||
assert payment.payment_method == "sbp"
|
||||
assert payment.is_paid is True
|
||||
assert stub.status_calls == ["BILL-1"]
|
||||
assert stub.payment_status_calls in ([], ["PAY-1"])
|
||||
assert result["remote_status"] == "SUCCESS"
|
||||
assert result["remote_data"] and "bill_status" in result["remote_data"]
|
||||
|
||||
@@ -6,7 +6,7 @@ from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace, ModuleType
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, Optional
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
@@ -829,6 +829,21 @@ async def test_get_pal24_payment_status_auto_finalize(monkeypatch: pytest.Monkey
|
||||
},
|
||||
}
|
||||
|
||||
async def get_payment_status(self, payment_id: str) -> Optional[Dict[str, Any]]:
|
||||
return None
|
||||
|
||||
async def get_bill_payments(self, bill_id: str) -> Optional[Dict[str, Any]]:
|
||||
return {
|
||||
"data": [
|
||||
{
|
||||
"id": "trs-auto-1",
|
||||
"bill_id": bill_id,
|
||||
"status": "SUCCESS",
|
||||
"payment_method": "SBP",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
service.pal24_service = DummyPal24Service()
|
||||
|
||||
fake_session = FakeSession()
|
||||
|
||||
Reference in New Issue
Block a user