Initial commit: VPN Telegram bot (sanitized defaults)
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
"""Автозачисление по уникальному коду 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,
|
||||
)
|
||||
Reference in New Issue
Block a user