Files
remnawave-bedolaga-telegram…/app/database/crud/wata.py
T
Fringg 1f0fef114b refactor: complete structlog migration with contextvars, kwargs, and logging hardening
- Add ContextVarsMiddleware for automatic user_id/chat_id/username binding
  via structlog contextvars (aiogram) and http_method/http_path (FastAPI)
- Use bound_contextvars() context manager instead of clear_contextvars()
  to safely restore previous state instead of wiping all context
- Register ContextVarsMiddleware as outermost middleware (before GlobalError)
  so all error logs include user context
- Replace structlog.get_logger() with structlog.get_logger(__name__) across
  270 calls in 265 files for meaningful logger names
- Switch wrapper_class from BoundLogger to make_filtering_bound_logger()
  for pre-processor level filtering (performance optimization)
- Migrate 1411 %-style positional arg logger calls to structlog kwargs
  style across 161 files via AST script
- Migrate log_rotation_service.py from stdlib logging to structlog
- Add payment module prefixes to TelegramNotifierProcessor.IGNORED_LOGGER_PREFIXES
  and ExcludePaymentFilter.PAYMENT_MODULES to prevent payment data leaking
  to Telegram notifications and general log files
- Fix LoggingMiddleware: add from_user null-safety for channel posts,
  switch time.time() to time.monotonic() for duration measurement
- Remove duplicate logger assignments in purchase.py, config.py,
  inline.py, and admin/payments.py
2026-02-16 09:18:12 +03:00

154 lines
4.3 KiB
Python

"""CRUD helpers for WATA payment records."""
from datetime import datetime
from typing import Any
import structlog
from sqlalchemy import select, update
from sqlalchemy.ext.asyncio import AsyncSession
from app.database.models import WataPayment
logger = structlog.get_logger(__name__)
async def create_wata_payment(
db: AsyncSession,
*,
user_id: int,
payment_link_id: str,
amount_kopeks: int,
currency: str,
description: str | None,
status: str,
type_: str | None,
url: str | None,
order_id: str | None = None,
metadata: dict[str, Any] | None = None,
expires_at: datetime | None = None,
terminal_public_id: str | None = None,
success_redirect_url: str | None = None,
fail_redirect_url: str | None = None,
) -> WataPayment:
payment = WataPayment(
user_id=user_id,
payment_link_id=payment_link_id,
order_id=order_id,
amount_kopeks=amount_kopeks,
currency=currency,
description=description,
status=status,
type=type_,
url=url,
metadata_json=metadata or {},
expires_at=expires_at,
terminal_public_id=terminal_public_id,
success_redirect_url=success_redirect_url,
fail_redirect_url=fail_redirect_url,
)
db.add(payment)
await db.commit()
await db.refresh(payment)
logger.info(
'Создан Wata платеж # для пользователя : копеек (статус)',
payment_id=payment.id,
user_id=user_id,
amount_kopeks=amount_kopeks,
status=status,
)
return payment
async def get_wata_payment_by_id(
db: AsyncSession,
payment_id: int,
) -> WataPayment | None:
result = await db.execute(select(WataPayment).where(WataPayment.id == payment_id))
return result.scalar_one_or_none()
async def get_wata_payment_by_link_id(
db: AsyncSession,
payment_link_id: str,
) -> WataPayment | None:
result = await db.execute(select(WataPayment).where(WataPayment.payment_link_id == payment_link_id))
return result.scalar_one_or_none()
async def get_wata_payment_by_order_id(
db: AsyncSession,
order_id: str,
) -> WataPayment | None:
result = await db.execute(select(WataPayment).where(WataPayment.order_id == order_id))
return result.scalar_one_or_none()
async def update_wata_payment_status(
db: AsyncSession,
payment: WataPayment,
*,
status: str | None = None,
is_paid: bool | None = None,
paid_at: datetime | None = None,
last_status: str | None = None,
url: str | None = None,
metadata: dict[str, Any] | None = None,
callback_payload: dict[str, Any] | None = None,
terminal_public_id: str | None = None,
) -> WataPayment:
update_values: dict[str, Any] = {}
if status is not None:
update_values['status'] = status
if is_paid is not None:
update_values['is_paid'] = is_paid
if paid_at is not None:
update_values['paid_at'] = paid_at
if last_status is not None:
update_values['last_status'] = last_status
if url is not None:
update_values['url'] = url
if metadata is not None:
update_values['metadata_json'] = metadata
if callback_payload is not None:
update_values['callback_payload'] = callback_payload
if terminal_public_id is not None:
update_values['terminal_public_id'] = terminal_public_id
if not update_values:
return payment
await db.execute(update(WataPayment).where(WataPayment.id == payment.id).values(**update_values))
await db.commit()
await db.refresh(payment)
logger.info(
'Обновлен Wata платеж : статус is_paid',
payment_link_id=payment.payment_link_id,
payment_status=payment.status,
is_paid=payment.is_paid,
)
return payment
async def link_wata_payment_to_transaction(
db: AsyncSession,
payment: WataPayment,
transaction_id: int,
) -> WataPayment:
await db.execute(update(WataPayment).where(WataPayment.id == payment.id).values(transaction_id=transaction_id))
await db.commit()
await db.refresh(payment)
logger.info(
'Wata платеж привязан к транзакции', payment_link_id=payment.payment_link_id, transaction_id=transaction_id
)
return payment