fix: register all providers in payment search and verification services

The admin Payments page filter and pending payments tab were missing newer
providers (paypear, rollypay, aurapay, etoplatezhi, antilopay, jupiter, donut,
lava) because they were never registered in the search/verification registries.
Customer payments via these providers were invisible in admin filtering.

payment_search_service.py:
- Add 8 _search_<provider> functions matching the existing pattern
- Register them in _PROVIDER_SEARCH_MAP (now 22 methods total)
- Filter dropdown and stats.by_method now include all providers

payment_verification_service.py:
- Add 8 _is_<provider>_pending and _fetch_<provider>_payments functions
- Wire them into list_recent_pending_payments and get_payment_record
- Add display name and is_enabled dispatch branches for all 8
- Register paypear / rollypay / aurapay in SUPPORTED_MANUAL_CHECK_METHODS and
  SUPPORTED_AUTO_CHECK_METHODS (they have full API+DB sync via check_*)
- Wire them into run_manual_check
- etoplatezhi / antilopay / jupiter / donut / lava remain webhook-driven and
  appear in pending tab without manual-check button (no fake API sync)
This commit is contained in:
Fringg
2026-05-04 20:43:47 +03:00
parent afea054c8f
commit cd8be32671
2 changed files with 751 additions and 0 deletions
+290
View File
@@ -15,17 +15,25 @@ from sqlalchemy.orm import selectinload
from sqlalchemy.types import String as SAString from sqlalchemy.types import String as SAString
from app.database.models import ( from app.database.models import (
AntilopayPayment,
AuraPayPayment,
CloudPaymentsPayment, CloudPaymentsPayment,
CryptoBotPayment, CryptoBotPayment,
DonutPayment,
EtoplatezhiPayment,
FreekassaPayment, FreekassaPayment,
HeleketPayment, HeleketPayment,
JupiterPayment,
KassaAiPayment, KassaAiPayment,
LavaPayment,
MulenPayPayment, MulenPayPayment,
OverpayPayment, OverpayPayment,
Pal24Payment, Pal24Payment,
PaymentMethod, PaymentMethod,
PayPearPayment,
PlategaPayment, PlategaPayment,
RioPayPayment, RioPayPayment,
RollyPayPayment,
SeverPayPayment, SeverPayPayment,
Transaction, Transaction,
TransactionType, TransactionType,
@@ -683,6 +691,280 @@ async def _search_overpay(db: AsyncSession, params: SearchParams) -> list[Pendin
return records return records
async def _search_paypear(db: AsyncSession, params: SearchParams) -> list[PendingPayment]:
stmt = select(PayPearPayment).options(selectinload(PayPearPayment.user)).order_by(desc(PayPearPayment.created_at))
stmt = _apply_date_filter(stmt, PayPearPayment.created_at, params.cutoff, params.upper_bound)
if params.search:
kind = _detect_user_search_kind(params.search)
if kind == _UserSearchKind.INVOICE:
conditions = [
PayPearPayment.order_id.ilike(f'%{_escape_like(params.search)}%'),
PayPearPayment.paypear_id.ilike(f'%{_escape_like(params.search)}%'),
]
stmt = stmt.where(or_(*conditions))
else:
stmt = _apply_user_join_filter(stmt, PayPearPayment, kind, params.search)
stmt = stmt.limit(MAX_RECORDS_PER_PROVIDER)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
record = _build_record(
PaymentMethod.PAYPEAR,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _search_rollypay(db: AsyncSession, params: SearchParams) -> list[PendingPayment]:
stmt = (
select(RollyPayPayment).options(selectinload(RollyPayPayment.user)).order_by(desc(RollyPayPayment.created_at))
)
stmt = _apply_date_filter(stmt, RollyPayPayment.created_at, params.cutoff, params.upper_bound)
if params.search:
kind = _detect_user_search_kind(params.search)
if kind == _UserSearchKind.INVOICE:
conditions = [
RollyPayPayment.order_id.ilike(f'%{_escape_like(params.search)}%'),
RollyPayPayment.rollypay_payment_id.ilike(f'%{_escape_like(params.search)}%'),
]
stmt = stmt.where(or_(*conditions))
else:
stmt = _apply_user_join_filter(stmt, RollyPayPayment, kind, params.search)
stmt = stmt.limit(MAX_RECORDS_PER_PROVIDER)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
record = _build_record(
PaymentMethod.ROLLYPAY,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _search_aurapay(db: AsyncSession, params: SearchParams) -> list[PendingPayment]:
stmt = select(AuraPayPayment).options(selectinload(AuraPayPayment.user)).order_by(desc(AuraPayPayment.created_at))
stmt = _apply_date_filter(stmt, AuraPayPayment.created_at, params.cutoff, params.upper_bound)
if params.search:
kind = _detect_user_search_kind(params.search)
if kind == _UserSearchKind.INVOICE:
conditions = [
AuraPayPayment.order_id.ilike(f'%{_escape_like(params.search)}%'),
AuraPayPayment.aurapay_invoice_id.ilike(f'%{_escape_like(params.search)}%'),
]
stmt = stmt.where(or_(*conditions))
else:
stmt = _apply_user_join_filter(stmt, AuraPayPayment, kind, params.search)
stmt = stmt.limit(MAX_RECORDS_PER_PROVIDER)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
record = _build_record(
PaymentMethod.AURAPAY,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _search_etoplatezhi(db: AsyncSession, params: SearchParams) -> list[PendingPayment]:
stmt = (
select(EtoplatezhiPayment)
.options(selectinload(EtoplatezhiPayment.user))
.order_by(desc(EtoplatezhiPayment.created_at))
)
stmt = _apply_date_filter(stmt, EtoplatezhiPayment.created_at, params.cutoff, params.upper_bound)
if params.search:
kind = _detect_user_search_kind(params.search)
if kind == _UserSearchKind.INVOICE:
conditions = [
EtoplatezhiPayment.order_id.ilike(f'%{_escape_like(params.search)}%'),
EtoplatezhiPayment.etoplatezhi_payment_id.ilike(f'%{_escape_like(params.search)}%'),
]
stmt = stmt.where(or_(*conditions))
else:
stmt = _apply_user_join_filter(stmt, EtoplatezhiPayment, kind, params.search)
stmt = stmt.limit(MAX_RECORDS_PER_PROVIDER)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
record = _build_record(
PaymentMethod.ETOPLATEZHI,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _search_antilopay(db: AsyncSession, params: SearchParams) -> list[PendingPayment]:
stmt = (
select(AntilopayPayment)
.options(selectinload(AntilopayPayment.user))
.order_by(desc(AntilopayPayment.created_at))
)
stmt = _apply_date_filter(stmt, AntilopayPayment.created_at, params.cutoff, params.upper_bound)
if params.search:
kind = _detect_user_search_kind(params.search)
if kind == _UserSearchKind.INVOICE:
conditions = [
AntilopayPayment.order_id.ilike(f'%{_escape_like(params.search)}%'),
AntilopayPayment.antilopay_payment_id.ilike(f'%{_escape_like(params.search)}%'),
]
stmt = stmt.where(or_(*conditions))
else:
stmt = _apply_user_join_filter(stmt, AntilopayPayment, kind, params.search)
stmt = stmt.limit(MAX_RECORDS_PER_PROVIDER)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
record = _build_record(
PaymentMethod.ANTILOPAY,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _search_jupiter(db: AsyncSession, params: SearchParams) -> list[PendingPayment]:
stmt = select(JupiterPayment).options(selectinload(JupiterPayment.user)).order_by(desc(JupiterPayment.created_at))
stmt = _apply_date_filter(stmt, JupiterPayment.created_at, params.cutoff, params.upper_bound)
if params.search:
kind = _detect_user_search_kind(params.search)
if kind == _UserSearchKind.INVOICE:
conditions = [
JupiterPayment.order_id.ilike(f'%{_escape_like(params.search)}%'),
JupiterPayment.jupiter_transaction_id.ilike(f'%{_escape_like(params.search)}%'),
]
stmt = stmt.where(or_(*conditions))
else:
stmt = _apply_user_join_filter(stmt, JupiterPayment, kind, params.search)
stmt = stmt.limit(MAX_RECORDS_PER_PROVIDER)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
record = _build_record(
PaymentMethod.JUPITER,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _search_donut(db: AsyncSession, params: SearchParams) -> list[PendingPayment]:
stmt = select(DonutPayment).options(selectinload(DonutPayment.user)).order_by(desc(DonutPayment.created_at))
stmt = _apply_date_filter(stmt, DonutPayment.created_at, params.cutoff, params.upper_bound)
if params.search:
kind = _detect_user_search_kind(params.search)
if kind == _UserSearchKind.INVOICE:
conditions = [
DonutPayment.order_id.ilike(f'%{_escape_like(params.search)}%'),
DonutPayment.donut_transaction_id.ilike(f'%{_escape_like(params.search)}%'),
]
stmt = stmt.where(or_(*conditions))
else:
stmt = _apply_user_join_filter(stmt, DonutPayment, kind, params.search)
stmt = stmt.limit(MAX_RECORDS_PER_PROVIDER)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
record = _build_record(
PaymentMethod.DONUT,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _search_lava(db: AsyncSession, params: SearchParams) -> list[PendingPayment]:
stmt = select(LavaPayment).options(selectinload(LavaPayment.user)).order_by(desc(LavaPayment.created_at))
stmt = _apply_date_filter(stmt, LavaPayment.created_at, params.cutoff, params.upper_bound)
if params.search:
kind = _detect_user_search_kind(params.search)
if kind == _UserSearchKind.INVOICE:
conditions = [
LavaPayment.order_id.ilike(f'%{_escape_like(params.search)}%'),
LavaPayment.lava_invoice_id.ilike(f'%{_escape_like(params.search)}%'),
]
stmt = stmt.where(or_(*conditions))
else:
stmt = _apply_user_join_filter(stmt, LavaPayment, kind, params.search)
stmt = stmt.limit(MAX_RECORDS_PER_PROVIDER)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
record = _build_record(
PaymentMethod.LAVA,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _search_stars(db: AsyncSession, params: SearchParams) -> list[PendingPayment]: async def _search_stars(db: AsyncSession, params: SearchParams) -> list[PendingPayment]:
stmt = ( stmt = (
select(Transaction) select(Transaction)
@@ -737,6 +1019,14 @@ _PROVIDER_SEARCH_MAP: dict[PaymentMethod, Any] = {
PaymentMethod.RIOPAY: _search_riopay, PaymentMethod.RIOPAY: _search_riopay,
PaymentMethod.SEVERPAY: _search_severpay, PaymentMethod.SEVERPAY: _search_severpay,
PaymentMethod.OVERPAY: _search_overpay, PaymentMethod.OVERPAY: _search_overpay,
PaymentMethod.PAYPEAR: _search_paypear,
PaymentMethod.ROLLYPAY: _search_rollypay,
PaymentMethod.AURAPAY: _search_aurapay,
PaymentMethod.ETOPLATEZHI: _search_etoplatezhi,
PaymentMethod.ANTILOPAY: _search_antilopay,
PaymentMethod.JUPITER: _search_jupiter,
PaymentMethod.DONUT: _search_donut,
PaymentMethod.LAVA: _search_lava,
PaymentMethod.TELEGRAM_STARS: _search_stars, PaymentMethod.TELEGRAM_STARS: _search_stars,
} }
@@ -18,16 +18,24 @@ from sqlalchemy.orm import selectinload
from app.config import settings from app.config import settings
from app.database.database import AsyncSessionLocal from app.database.database import AsyncSessionLocal
from app.database.models import ( from app.database.models import (
AntilopayPayment,
AuraPayPayment,
CloudPaymentsPayment, CloudPaymentsPayment,
CryptoBotPayment, CryptoBotPayment,
DonutPayment,
EtoplatezhiPayment,
FreekassaPayment, FreekassaPayment,
HeleketPayment, HeleketPayment,
JupiterPayment,
KassaAiPayment, KassaAiPayment,
LavaPayment,
MulenPayPayment, MulenPayPayment,
Pal24Payment, Pal24Payment,
PaymentMethod, PaymentMethod,
PayPearPayment,
PlategaPayment, PlategaPayment,
RioPayPayment, RioPayPayment,
RollyPayPayment,
SeverPayPayment, SeverPayPayment,
Transaction, Transaction,
TransactionType, TransactionType,
@@ -77,6 +85,11 @@ SUPPORTED_MANUAL_CHECK_METHODS: frozenset[PaymentMethod] = frozenset(
PaymentMethod.RIOPAY, PaymentMethod.RIOPAY,
PaymentMethod.SEVERPAY, PaymentMethod.SEVERPAY,
PaymentMethod.OVERPAY, PaymentMethod.OVERPAY,
PaymentMethod.PAYPEAR,
PaymentMethod.ROLLYPAY,
PaymentMethod.AURAPAY,
# ETOPLATEZHI / ANTILOPAY / JUPITER / DONUT / LAVA — webhook-driven,
# без API-метода синхронизации БД, manual check не реализован.
} }
) )
@@ -98,6 +111,9 @@ SUPPORTED_AUTO_CHECK_METHODS: frozenset[PaymentMethod] = frozenset(
PaymentMethod.RIOPAY, PaymentMethod.RIOPAY,
PaymentMethod.SEVERPAY, PaymentMethod.SEVERPAY,
PaymentMethod.OVERPAY, PaymentMethod.OVERPAY,
PaymentMethod.PAYPEAR,
PaymentMethod.ROLLYPAY,
PaymentMethod.AURAPAY,
} }
) )
@@ -129,6 +145,22 @@ def method_display_name(method: PaymentMethod) -> str:
return settings.get_severpay_display_name() return settings.get_severpay_display_name()
if method == PaymentMethod.OVERPAY: if method == PaymentMethod.OVERPAY:
return settings.get_overpay_display_name() return settings.get_overpay_display_name()
if method == PaymentMethod.PAYPEAR:
return settings.get_paypear_display_name()
if method == PaymentMethod.ROLLYPAY:
return settings.get_rollypay_display_name()
if method == PaymentMethod.AURAPAY:
return settings.get_aurapay_display_name()
if method == PaymentMethod.ETOPLATEZHI:
return settings.get_etoplatezhi_display_name()
if method == PaymentMethod.ANTILOPAY:
return settings.get_antilopay_display_name()
if method == PaymentMethod.JUPITER:
return settings.get_jupiter_display_name()
if method == PaymentMethod.DONUT:
return settings.get_donut_display_name()
if method == PaymentMethod.LAVA:
return settings.get_lava_display_name()
if method == PaymentMethod.TELEGRAM_STARS: if method == PaymentMethod.TELEGRAM_STARS:
return 'Telegram Stars' return 'Telegram Stars'
return method.value return method.value
@@ -161,6 +193,22 @@ def _method_is_enabled(method: PaymentMethod) -> bool:
return settings.is_severpay_enabled() return settings.is_severpay_enabled()
if method == PaymentMethod.OVERPAY: if method == PaymentMethod.OVERPAY:
return settings.is_overpay_enabled() return settings.is_overpay_enabled()
if method == PaymentMethod.PAYPEAR:
return settings.is_paypear_enabled()
if method == PaymentMethod.ROLLYPAY:
return settings.is_rollypay_enabled()
if method == PaymentMethod.AURAPAY:
return settings.is_aurapay_enabled()
if method == PaymentMethod.ETOPLATEZHI:
return settings.is_etoplatezhi_enabled()
if method == PaymentMethod.ANTILOPAY:
return settings.is_antilopay_enabled()
if method == PaymentMethod.JUPITER:
return settings.is_jupiter_enabled()
if method == PaymentMethod.DONUT:
return settings.is_donut_enabled()
if method == PaymentMethod.LAVA:
return settings.is_lava_enabled()
return False return False
@@ -410,6 +458,62 @@ def _is_riopay_pending(payment: RioPayPayment) -> bool:
return status in {'pending'} return status in {'pending'}
def _is_paypear_pending(payment: PayPearPayment) -> bool:
if payment.is_paid:
return False
status = (payment.status or '').lower()
return status in {'pending', 'created', 'processing'}
def _is_rollypay_pending(payment: RollyPayPayment) -> bool:
if payment.is_paid:
return False
status = (payment.status or '').lower()
return status in {'pending', 'created', 'processing'}
def _is_aurapay_pending(payment: AuraPayPayment) -> bool:
if payment.is_paid:
return False
status = (payment.status or '').lower()
return status in {'pending', 'created', 'processing'}
def _is_etoplatezhi_pending(payment: EtoplatezhiPayment) -> bool:
if payment.is_paid:
return False
status = (payment.status or '').lower()
return status in {'pending', 'created', 'processing'}
def _is_antilopay_pending(payment: AntilopayPayment) -> bool:
if payment.is_paid:
return False
status = (payment.status or '').lower()
return status in {'pending', 'created', 'processing'}
def _is_jupiter_pending(payment: JupiterPayment) -> bool:
if payment.is_paid:
return False
status = (payment.status or '').lower()
return status in {'pending', 'created', 'processing'}
def _is_donut_pending(payment: DonutPayment) -> bool:
if payment.is_paid:
return False
status = (payment.status or '').lower()
return status in {'pending', 'created', 'processing'}
def _is_lava_pending(payment: LavaPayment) -> bool:
if payment.is_paid:
return False
status = (payment.status or '').lower()
return status in {'pending', 'created', 'processing'}
def _parse_cryptobot_amount_kopeks(payment: CryptoBotPayment) -> int: def _parse_cryptobot_amount_kopeks(payment: CryptoBotPayment) -> int:
payload = payment.payload or '' payload = payment.payload or ''
match = re.search(r'_(\d+)$', payload) match = re.search(r'_(\d+)$', payload)
@@ -779,6 +883,214 @@ async def _fetch_severpay_payments(db: AsyncSession, cutoff: datetime) -> list[P
return records return records
async def _fetch_paypear_payments(db: AsyncSession, cutoff: datetime) -> list[PendingPayment]:
stmt = (
select(PayPearPayment)
.options(selectinload(PayPearPayment.user))
.where(PayPearPayment.created_at >= cutoff)
.order_by(desc(PayPearPayment.created_at))
)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
if not _is_paypear_pending(payment):
continue
record = _build_record(
PaymentMethod.PAYPEAR,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _fetch_rollypay_payments(db: AsyncSession, cutoff: datetime) -> list[PendingPayment]:
stmt = (
select(RollyPayPayment)
.options(selectinload(RollyPayPayment.user))
.where(RollyPayPayment.created_at >= cutoff)
.order_by(desc(RollyPayPayment.created_at))
)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
if not _is_rollypay_pending(payment):
continue
record = _build_record(
PaymentMethod.ROLLYPAY,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _fetch_aurapay_payments(db: AsyncSession, cutoff: datetime) -> list[PendingPayment]:
stmt = (
select(AuraPayPayment)
.options(selectinload(AuraPayPayment.user))
.where(AuraPayPayment.created_at >= cutoff)
.order_by(desc(AuraPayPayment.created_at))
)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
if not _is_aurapay_pending(payment):
continue
record = _build_record(
PaymentMethod.AURAPAY,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _fetch_etoplatezhi_payments(db: AsyncSession, cutoff: datetime) -> list[PendingPayment]:
stmt = (
select(EtoplatezhiPayment)
.options(selectinload(EtoplatezhiPayment.user))
.where(EtoplatezhiPayment.created_at >= cutoff)
.order_by(desc(EtoplatezhiPayment.created_at))
)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
if not _is_etoplatezhi_pending(payment):
continue
record = _build_record(
PaymentMethod.ETOPLATEZHI,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _fetch_antilopay_payments(db: AsyncSession, cutoff: datetime) -> list[PendingPayment]:
stmt = (
select(AntilopayPayment)
.options(selectinload(AntilopayPayment.user))
.where(AntilopayPayment.created_at >= cutoff)
.order_by(desc(AntilopayPayment.created_at))
)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
if not _is_antilopay_pending(payment):
continue
record = _build_record(
PaymentMethod.ANTILOPAY,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _fetch_jupiter_payments(db: AsyncSession, cutoff: datetime) -> list[PendingPayment]:
stmt = (
select(JupiterPayment)
.options(selectinload(JupiterPayment.user))
.where(JupiterPayment.created_at >= cutoff)
.order_by(desc(JupiterPayment.created_at))
)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
if not _is_jupiter_pending(payment):
continue
record = _build_record(
PaymentMethod.JUPITER,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _fetch_donut_payments(db: AsyncSession, cutoff: datetime) -> list[PendingPayment]:
stmt = (
select(DonutPayment)
.options(selectinload(DonutPayment.user))
.where(DonutPayment.created_at >= cutoff)
.order_by(desc(DonutPayment.created_at))
)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
if not _is_donut_pending(payment):
continue
record = _build_record(
PaymentMethod.DONUT,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _fetch_lava_payments(db: AsyncSession, cutoff: datetime) -> list[PendingPayment]:
stmt = (
select(LavaPayment)
.options(selectinload(LavaPayment.user))
.where(LavaPayment.created_at >= cutoff)
.order_by(desc(LavaPayment.created_at))
)
result = await db.execute(stmt)
records: list[PendingPayment] = []
for payment in result.scalars().all():
if not _is_lava_pending(payment):
continue
record = _build_record(
PaymentMethod.LAVA,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if record:
records.append(record)
return records
async def _fetch_stars_transactions(db: AsyncSession, cutoff: datetime) -> list[PendingPayment]: async def _fetch_stars_transactions(db: AsyncSession, cutoff: datetime) -> list[PendingPayment]:
stmt = ( stmt = (
select(Transaction) select(Transaction)
@@ -828,6 +1140,14 @@ async def list_recent_pending_payments(
await _fetch_kassa_ai_payments(db, cutoff), await _fetch_kassa_ai_payments(db, cutoff),
await _fetch_riopay_payments(db, cutoff), await _fetch_riopay_payments(db, cutoff),
await _fetch_severpay_payments(db, cutoff), await _fetch_severpay_payments(db, cutoff),
await _fetch_paypear_payments(db, cutoff),
await _fetch_rollypay_payments(db, cutoff),
await _fetch_aurapay_payments(db, cutoff),
await _fetch_etoplatezhi_payments(db, cutoff),
await _fetch_antilopay_payments(db, cutoff),
await _fetch_jupiter_payments(db, cutoff),
await _fetch_donut_payments(db, cutoff),
await _fetch_lava_payments(db, cutoff),
await _fetch_stars_transactions(db, cutoff), await _fetch_stars_transactions(db, cutoff),
) )
@@ -1026,6 +1346,126 @@ async def get_payment_record(
expires_at=getattr(payment, 'expires_at', None), expires_at=getattr(payment, 'expires_at', None),
) )
if method == PaymentMethod.PAYPEAR:
payment = await db.get(PayPearPayment, local_payment_id)
if not payment:
return None
await db.refresh(payment, attribute_names=['user'])
return _build_record(
method,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if method == PaymentMethod.ROLLYPAY:
payment = await db.get(RollyPayPayment, local_payment_id)
if not payment:
return None
await db.refresh(payment, attribute_names=['user'])
return _build_record(
method,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if method == PaymentMethod.AURAPAY:
payment = await db.get(AuraPayPayment, local_payment_id)
if not payment:
return None
await db.refresh(payment, attribute_names=['user'])
return _build_record(
method,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if method == PaymentMethod.ETOPLATEZHI:
payment = await db.get(EtoplatezhiPayment, local_payment_id)
if not payment:
return None
await db.refresh(payment, attribute_names=['user'])
return _build_record(
method,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if method == PaymentMethod.ANTILOPAY:
payment = await db.get(AntilopayPayment, local_payment_id)
if not payment:
return None
await db.refresh(payment, attribute_names=['user'])
return _build_record(
method,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if method == PaymentMethod.JUPITER:
payment = await db.get(JupiterPayment, local_payment_id)
if not payment:
return None
await db.refresh(payment, attribute_names=['user'])
return _build_record(
method,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if method == PaymentMethod.DONUT:
payment = await db.get(DonutPayment, local_payment_id)
if not payment:
return None
await db.refresh(payment, attribute_names=['user'])
return _build_record(
method,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if method == PaymentMethod.LAVA:
payment = await db.get(LavaPayment, local_payment_id)
if not payment:
return None
await db.refresh(payment, attribute_names=['user'])
return _build_record(
method,
payment,
identifier=payment.order_id,
amount_kopeks=payment.amount_kopeks,
status=payment.status or '',
is_paid=bool(payment.is_paid),
expires_at=getattr(payment, 'expires_at', None),
)
if method == PaymentMethod.TELEGRAM_STARS: if method == PaymentMethod.TELEGRAM_STARS:
transaction = await db.get(Transaction, local_payment_id) transaction = await db.get(Transaction, local_payment_id)
if not transaction: if not transaction:
@@ -1098,6 +1538,27 @@ async def run_manual_check(
payment = result.get('payment') if result else None payment = result.get('payment') if result else None
else: else:
payment = None payment = None
elif method == PaymentMethod.PAYPEAR:
paypear_payment = await db.get(PayPearPayment, local_payment_id)
if paypear_payment:
result = await payment_service.check_paypear_payment_status(db, paypear_payment.order_id)
payment = result.get('payment') if result else None
else:
payment = None
elif method == PaymentMethod.ROLLYPAY:
rollypay_payment = await db.get(RollyPayPayment, local_payment_id)
if rollypay_payment:
result = await payment_service.check_rollypay_payment_status(db, rollypay_payment.order_id)
payment = result.get('payment') if result else None
else:
payment = None
elif method == PaymentMethod.AURAPAY:
aurapay_payment = await db.get(AuraPayPayment, local_payment_id)
if aurapay_payment:
result = await payment_service.check_aurapay_payment_status(db, aurapay_payment.order_id)
payment = result.get('payment') if result else None
else:
payment = None
else: else:
logger.warning('Manual check requested for unsupported method', method=method) logger.warning('Manual check requested for unsupported method', method=method)
return None return None