Files
vpn-telegram-bot/services/digiseller_fulfill.py
T

128 lines
3.8 KiB
Python

"""Автозачисление по уникальному коду 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"✅ <b>Баланс пополнен через Digiseller</b>\n\n"
f"+{amount:.0f}\n"
f"Счёт Digiseller: <code>{purchase.inv}</code>\n"
f"Доступно: <b>{balance:.0f} ₽</b>"
)
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,
)