Урок 7.2 — Shortcut-методы объектов API
Изучаем shortcut-методы объектов Invoice, Check, Balance, ExchangeRate — удобные инструменты для быстрых операций без прямого обращения к клиенту.
Shortcut-методы — это методы, которые вызываются непосредственно на объекте (например, invoice.update()) и внутри обращаются к клиенту, который создал этот объект. Тебе не нужно хранить ссылку на CryptoPay — объект сам знает, через какой клиент был получен, и использует его для API-запросов.
Shortcut-методы Invoice
Объект Invoice предоставляет несколько shortcut-методов для управления счётом. Рассмотрим каждый подробно.
Invoice.update()
Обновляет данные объекта из API. Полезно, когда нужно получить актуальный статус инвойса.
from aiosend import CryptoPay
cp = CryptoPay(token="1234:TOKEN")
# Создаём инвойс
invoice = await cp.create_invoice(amount=10, asset="USDT")
print(f"Статус: {invoice.status}") # active
# ...проходит время, инвойс оплачивают...
# Обновляем данные из API
await invoice.update()
print(f"Новый статус: {invoice.status}") # paid
print(f"Оплачено: {invoice.paid_amount} {invoice.paid_asset}")
print(f"Время оплаты: {invoice.paid_at}")
Invoice.delete()
Удаляет инвойс. Доступно только для неоплаченных счетов.
# Создаём и сразу удаляем (например, если ошиблись)
invoice = await cp.create_invoice(amount=100, asset="USDT")
print(f"Создан инвойс #{invoice.invoice_id}")
# Удаляем
result = await invoice.delete()
print(f"Удалён: {result}") # True
# Попытка удалить оплаченный инвойс вызовет ошибку
paid_invoice = await cp.get_invoice(invoice_id=123)
try:
await paid_invoice.delete()
except Exception as e:
print(f"Нельзя удалить: {e}")
Invoice.poll()
Ожидает оплату конкретного инвойса. Возвращает обновлённый объект после оплаты.
import asyncio
from aiosend import CryptoPay
async def main():
cp = CryptoPay(token="1234:TOKEN")
invoice = await cp.create_invoice(
amount=0.5, asset="TON",
description="Тестовый платёж",
)
print(f"Ссылка на оплату: {invoice.bot_invoice_url}")
# Ждём оплаты (по умолчанию таймаут 300 сек)
paid = await invoice.poll()
print(f"Инвойс #{paid.invoice_id} оплачен!")
print(f"Сумма: {paid.paid_amount} {paid.paid_asset}")
asyncio.run(main())
Метод poll() также принимает необязательные параметры:
| Параметр | Тип | Описание |
|---|---|---|
on_paid |
Callable | None |
Функция-колбэк, вызываемая после оплаты. Принимает invoice и **kwargs. |
**kwargs |
Any |
Произвольные аргументы, передаваемые в on_paid. |
async def after_payment(invoice, **kwargs):
user_id = kwargs.get("user_id")
print(f"Пользователь {user_id} оплатил инвойс #{invoice.invoice_id}")
invoice = await cp.create_invoice(amount=15, asset="USDT")
# Передаём колбэк и дополнительные данные
await invoice.poll(
on_paid=after_payment,
user_id=12345,
)
Invoice.qr
Свойство, возвращающее URL QR-кода для быстрой оплаты.
invoice = await cp.create_invoice(amount=25, asset="USDT")
# QR-код — это свойство (property), не метод
qr_url = invoice.qr
print(f"QR-код: {qr_url}")
# → https://qr.crypt.bot/?url=https://pay.crypt.bot/invoice/...
# Можно отправить пользователю как изображение
# в Telegram: bot.send_photo(chat_id, qr_url)
Shortcut-методы Check
Check (крипто-чек) — это объект, представляющий криптовалютный чек. У него есть свои shortcut-методы.
Check.update()
Обновляет данные чека из API.
from aiosend import CryptoPay
cp = CryptoPay(token="1234:TOKEN")
# Получаем существующий чек
check = await cp.get_checks(check_ids=[123])[0]
print(f"Статус: {check.status}") # active
# Обновляем
await check.update()
print(f"Новый статус: {check.status}")
Check.delete()
Удаляет чек. Доступно только для неактивированных чеков.
check = await cp.create_check(amount=10, asset="USDT")
print(f"Создан чек #{check.check_id}")
# Удаляем
result = await check.delete()
print(f"Результат удаления: {result}") # True
Check.poll()
Ожидает активации (получения) чека. Аналогичен invoice.poll().
check = await cp.create_check(amount=5, asset="TON")
print(f"Чек создан: {check.check_id}")
print(f"Ссылка: {check.bot_check_url}")
# Ждём активации
activated = await check.poll()
print(f"Чек #{activated.check_id} активирован!")
print(f"Активирован пользователем: {activated.activate_by}")
Check.qr
Свойство, возвращающее URL QR-кода для чека.
check = await cp.create_check(amount=10, asset="USDT")
print(f"QR-код чека: {check.qr}")
Check.get_image()
Генерирует URL изображения чека. Это не async метод, так как не делает HTTP-запросов — только формирует URL.
check = await cp.create_check(amount=100, asset="USDT")
# Получаем URL изображения чека
image_url = check.get_image()
print(f"Изображение чека: {image_url}")
# Можно отправить как картинку в Telegram:
# await bot.send_photo(chat_id, image_url, caption="Ваш чек!")
💡 get_image() — синхронный метод
get_image() не делает HTTP-запросов. Он просто формирует URL к сервису imggen.send.tg, который генерирует PNG-изображение чека. Поэтому его не нужно await'ить.
Shortcut-методы Balance
Объект Balance представляет баланс вашего приложения в определённой валюте. У него есть метод update().
Balance.update()
Запрашивает актуальный баланс из API.
from aiosend import CryptoPay
cp = CryptoPay(token="1234:TOKEN")
# Получаем все балансы
balances = await cp.get_balances()
for balance in balances:
print(f"{balance.asset}: {balance.amount}")
# Обновляем конкретный баланс
usdt_balance = next(b for b in balances if b.asset == "USDT")
print(f"Текущий USDT: {usdt_balance.amount}")
await usdt_balance.update()
print(f"Обновлённый USDT: {usdt_balance.amount}")
💡 Когда использовать Balance.update()?
После получения оплаты или создания/активации чека. Если ты работаешь через polling или webhook, обновляй баланс после каждого события, чтобы всегда иметь актуальные данные.
Shortcut-методы ExchangeRate
Объект ExchangeRate представляет курс обмена одной валюты на другую. У него также есть метод update().
ExchangeRate.update()
Обновляет курс из API.
from aiosend import CryptoPay
cp = CryptoPay(token="1234:TOKEN")
# Получаем все курсы
rates = await cp.get_exchange_rates()
# Находим курс USDT → USD
usdt_usd = next(
(r for r in rates if r.source == "USDT" and r.target == "USD"),
None
)
if usdt_usd:
print(f"1 USDT = {usdt_usd.rate} USD")
print(f"Актуален: {usdt_usd.is_valid}")
# Обновляем курс
await usdt_usd.update()
print(f"Новый курс: {usdt_usd.rate} USD")
⚠️ Курсы обновляются нечасто
Crypto Pay обновляет курсы не в реальном времени, а с некоторой периодичностью (обычно раз в несколько минут). Не ожидай, что update() даст другое значение, если прошло мало времени.
Полный пример: использование всех shortcut
import asyncio
from aiosend import CryptoPay
async def main():
cp = CryptoPay(token="1234:TOKEN")
# 1. INVOICE SHORTCUTS
print("=== INVOICE ===")
invoice = await cp.create_invoice(amount=10, asset="USDT")
print(f"Создан: #{invoice.invoice_id}, статус: {invoice.status}")
print(f"QR: {invoice.qr}")
await invoice.update()
print(f"Обновлён: статус={invoice.status}")
# invoice.delete() — удалит, если не оплачен
# 2. CHECK SHORTCUTS
print("\n=== CHECK ===")
check = await cp.create_check(amount=5, asset="TON")
print(f"Создан чек: #{check.check_id}")
print(f"QR: {check.qr}")
print(f"Изображение: {check.get_image()}")
await check.update()
print(f"Обновлён: статус={check.status}")
# 3. BALANCE SHORTCUTS
print("\n=== BALANCE ===")
balances = await cp.get_balances()
for bal in balances:
print(f"{bal.asset}: {bal.amount}")
await bal.update()
print(f" → после update: {bal.amount}")
# 4. EXCHANGE RATE SHORTCUTS
print("\n=== EXCHANGE RATES ===")
rates = await cp.get_exchange_rates()
for rate in rates[:5]: # только первые 5
print(f"{rate.source} → {rate.target}: {rate.rate}")
await rate.update()
print("\nГотово!")
asyncio.run(main())
Как это работает внутри?
Каждый объект (Invoice, Check, Balance, ExchangeRate) хранит ссылку на клиента, через который он был получен. Это происходит в момент десериализации ответа API — aiosend передаёт клиент во все создаваемые объекты.
class Invoice(BaseModel):
invoice_id: int
status: str
# ... другие поля
# Ссылка на клиента (устанавливается после создания)
_client: CryptoPay | None = None
async def update(self) -> None:
"""Обновляет данные инвойса из API."""
if self._client is None:
raise RuntimeError("Объект не привязан к клиенту")
updated = await self._client.get_invoice(
invoice_id=self.invoice_id
)
# Копируем все поля из обновлённого объекта
for field in self.model_fields:
setattr(self, field, getattr(updated, field))
async def delete(self) -> bool:
"""Удаляет инвойс."""
return await self._client.delete_invoice(
invoice_id=self.invoice_id
)
@property
def qr(self) -> str:
"""URL QR-кода."""
return self._client.session.network.get_qr(
self.bot_invoice_url
)
async def poll(self, on_paid=None, **kwargs):
"""Ожидает оплаты."""
return await self._client.poll(
invoice_id=self.invoice_id,
on_paid=on_paid,
**kwargs,
)
🔍 Зачем это нужно?
Благодаря тому, что объекты хранят ссылку на клиента, ты можешь передавать их в любые части приложения, и они сохраняют способность делать API-запросы. Это очень удобно: например, ты можешь сохранить объект Invoice в БД, а потом восстановить и вызвать invoice.update() без доступа к исходному клиенту.
Что важно запомнить
CryptoPay, используя сохранённую ссылку на клиента.Практическое задание
Задание: Мониторинг счетов и чеков через shortcut
Напиши скрипт, который:
- Создаёт 3 инвойса с разными суммами и assets
- Для каждого выводит QR-код
- Ожидает оплаты всех трёх через
invoice.poll() - После оплаты обновляет баланс через
balance.update() - Выводит финальный баланс по всем валютам
Подсказка:
import asyncio
from aiosend import CryptoPay
async def monitor_payments():
cp = CryptoPay(token="YOUR_TOKEN")
# Создаём инвойсы
invoices = []
for amount, asset in [(10, "USDT"), (0.5, "TON"), (5, "USDT")]:
inv = await cp.create_invoice(
amount=amount, asset=asset,
description=f"Тест {amount} {asset}",
)
invoices.append(inv)
print(f"Создан: {inv.bot_invoice_url} | QR: {inv.qr}")
# Ожидаем оплаты всех
for inv in invoices:
print(f"Ожидаем оплату #{inv.invoice_id}...")
paid = await inv.poll()
print(f"Оплачен: {paid.paid_amount} {paid.paid_asset}")
# Обновляем баланс
balances = await cp.get_balances()
for bal in balances:
await bal.update()
print(f"Баланс {bal.asset}: {bal.amount}")
asyncio.run(monitor_payments())
Урок 7.2: Shortcut-методы
5 вопросов