"""Автозачисление по уникальному коду Digiseller.""" from __future__ import annotations import logging from dataclasses import dataclass from aiogram import Bot from config import get_settings from services.db import Database from services.digiseller import Digiseller, DigisellerError from services.mailer import notify_important logger = logging.getLogger(__name__) @dataclass(frozen=True, slots=True) class DigisellerFulfillResult: ok: bool message: str amount: float = 0.0 balance: float = 0.0 telegram_id: int | None = None already: bool = False inv: int | None = None async def fulfill_digiseller_unique_code( *, db: Database, digiseller: Digiseller, unique_code: str, telegram_id_hint: int | None = None, bot: Bot | None = None, notify: bool = True, ) -> DigisellerFulfillResult: """Проверить код в Digiseller API и зачислить баланс. Идемпотентно.""" purchase = await digiseller.get_by_unique_code(unique_code) digiseller.assert_payable(purchase) amount = digiseller.credit_amount(purchase) telegram_id = digiseller.extract_telegram_id(purchase) or telegram_id_hint if not telegram_id: raise DigisellerError( "В платеже нет telegram_id. Открой оплату из бота " "(ссылка с твоим ID) или введи код вручную в боте." ) if db.digiseller_inv_used(purchase.inv) or db.digiseller_code_used( purchase.unique_code ): balance = db.get_balance(telegram_id) return DigisellerFulfillResult( ok=True, already=True, message="Этот платёж уже был зачислен ранее.", amount=amount, balance=balance, telegram_id=telegram_id, inv=purchase.inv, ) recorded = db.record_digiseller_payment( inv=purchase.inv, unique_code=purchase.unique_code, telegram_id=telegram_id, amount_rub=amount, product_id=purchase.product_id, ) if not recorded: balance = db.get_balance(telegram_id) return DigisellerFulfillResult( ok=True, already=True, message="Этот платёж уже был зачислен ранее.", amount=amount, balance=balance, telegram_id=telegram_id, inv=purchase.inv, ) balance = db.add_balance( telegram_id, amount, kind="digiseller_topup", meta=f"digi:{purchase.inv}:{purchase.unique_code}", ) try: await digiseller.mark_delivered(purchase.unique_code) except DigisellerError as exc: logger.warning( "Digiseller deliver failed inv=%s: %s", purchase.inv, exc ) text = ( f"✅ Баланс пополнен через Digiseller\n\n" f"+{amount:.0f} ₽\n" f"Счёт Digiseller: {purchase.inv}\n" f"Доступно: {balance:.0f} ₽" ) if notify: try: settings = get_settings(require_bot_token=False) await notify_important( db=db, settings=settings, telegram_id=telegram_id, html=text, subject="Баланс пополнен — VPN Service", bot=bot, ) except Exception as exc: # noqa: BLE001 logger.warning( "Digiseller notify failed tg=%s: %s", telegram_id, exc ) return DigisellerFulfillResult( ok=True, message=text, amount=amount, balance=balance, telegram_id=telegram_id, inv=purchase.inv, )