{"id":482005,"date":"2026-06-02T06:00:17","date_gmt":"2026-06-02T06:00:17","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=482005"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=482005","title":{"rendered":"\u041a\u0430\u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c Payme \u043a Telegram \u0431\u043e\u0442\u0443 \u043d\u0430 Python"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043a\u0430\u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c Payme \u2014 \u043e\u0434\u043d\u0443 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043f\u043b\u0430\u0442\u0451\u0436\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c \u0423\u0437\u0431\u0435\u043a\u0438\u0441\u0442\u0430\u043d\u0430 \u2014 \u043a Telegram \u0431\u043e\u0442\u0443 \u043d\u0430 Python.  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 aiopayme \u2014 async-first \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0441 \u0440\u043e\u0443\u0442\u0435\u0440\u0430\u043c\u0438 \u0438 dependency injection \u043a\u0430\u043a \u0432 aiogram \u0438 FastAPI.  \u0412 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0430\u0431\u043e\u0447\u0443\u044e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e: \u0431\u043e\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \/pay, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u043f\u043b\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 Payme, \u0431\u043e\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u043e\u043f\u043b\u0430\u0442\u0435.  <\/p>\n<h3>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430  <\/h3>\n<p><code>pip install aiopayme<\/code><\/p>\n<p>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 aiopayme?  aiopayme \u2014 \u044d\u0442\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f Python \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u043f\u043b\u0430\u0442\u0451\u0436\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b Payme.  \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u2014 \u0440\u043e\u0443\u0442\u0435\u0440\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u0437\u043d\u0430\u043a\u043e\u043c\u0430\u044f \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u043a\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441 aiogram \u0438\u043b\u0438 FastAPI:<\/p>\n<pre><code>from aiopayme import Routerrouter = Router()@router.check_perform_transaction()async def check_perform(ctx: CheckPerformTransactionCtx, db: AsyncSession): ...<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u2014 httpx. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043d\u0435 \u043d\u0430\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 ORM, \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0438\u043b\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.  <\/p>\n<h3>\u041c\u043e\u0434\u0435\u043b\u0438  <\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u2014 \u0437\u0430\u043a\u0430\u0437 \u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e Payme. <\/p>\n<pre><code># models\/order.pyimport enumfrom sqlalchemy import Column, BigInteger, Integer, Stringfrom sqlalchemy.orm import DeclarativeBaseclass Base(DeclarativeBase):    passclass OrderStatus(enum.Enum):    PENDING = \"pending\"    PAID = \"paid\"    CANCELED = \"canceled\"class Order(Base):    __tablename__ = \"orders\"    id = Column(Integer, primary_key=True)    telegram_id = Column(BigInteger, nullable=False)    amount = Column(BigInteger, nullable=False)    status = Column(String, default=OrderStatus.PENDING.value)    payme_transaction_id = Column(String, nullable=True)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code># models\/payme.pyfrom sqlalchemy import Column, Integer, String, BigIntegerfrom models.order import Baseclass PaymeTransaction(Base):    __tablename__ = \"payme_transactions\"    id = Column(Integer, primary_key=True)    payme_id = Column(String, unique=True, nullable=False)    order_id = Column(Integer, nullable=True)    state = Column(Integer, default=1)    amount = Column(BigInteger, nullable=False)    create_time = Column(BigInteger, nullable=False)    perform_time = Column(BigInteger, default=0)    cancel_time = Column(BigInteger, default=0)    reason = Column(Integer, nullable=True)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>PaymeService  <\/h3>\n<p>\u0412\u044b\u043d\u0435\u0441\u0435\u043c \u0432\u0441\u044e \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441. \u042d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u044b \u0447\u0438\u0441\u0442\u044b\u043c\u0438  \u0438 \u043b\u043e\u0433\u0438\u043a\u0443 \u043b\u0435\u0433\u043a\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0439. \u0421\u043e\u0437\u0434\u0430\u0451\u043c services\/payme.py:  <\/p>\n<pre><code># services\/payme.pyfrom sqlalchemy import select, updatefrom sqlalchemy.ext.asyncio import AsyncSessionfrom aiopayme.exceptions import Errorsfrom aiopayme.utils import time_to_paymefrom aiopayme.types import (    CheckPerformTransactionCtx,    CreateTransactionCtx,    PerformTransactionCtx,    CancelTransactionCtx,    CheckTransactionCtx,    GetStatementCtx,)from models import OrderStatus, Order, PaymeTransactionclass PaymeService:    def __init__(self, db: AsyncSession):        self.db = db    async def get_order(self, order_id) -&gt; Order | None:        return await self.db.scalar(            select(Order).where(Order.id == int(order_id))        )    async def get_transaction(self, payme_id: str) -&gt; PaymeTransaction | None:        return await self.db.scalar(            select(PaymeTransaction).where(PaymeTransaction.payme_id == payme_id)        )    async def get_active_transaction(self, order_id: int) -&gt; PaymeTransaction | None:        return await self.db.scalar(            select(PaymeTransaction).where(                PaymeTransaction.order_id == order_id,                PaymeTransaction.state == 1,            )        )    async def get_transactions(self, from_time: int, to_time: int):        return (await self.db.scalars(            select(PaymeTransaction).where(                PaymeTransaction.create_time &gt;= from_time,                PaymeTransaction.create_time &lt;= to_time,            )        )).all()    async def check_perform(self, ctx: CheckPerformTransactionCtx):        order = await self.get_order(ctx.account.order_id)        if not order:            raise Errors.invalid_account()        if order.amount * 100 != ctx.amount:            raise Errors.invalid_amount()        return ctx.ok(allow=True)    async def create_transaction(self, ctx: CreateTransactionCtx):        tx = await self.get_transaction(ctx.payme_id)        order = await self.get_order(ctx.account.order_id)        if not order:            raise Errors.invalid_account()        if order.amount * 100 != ctx.amount:            raise Errors.invalid_amount()        if tx:            if tx.state == -1:                raise Errors.unable_to_perform()            return ctx.ok(transaction_id=tx.payme_id, create_time=tx.create_time)        if order.status == OrderStatus.PAID:            raise Errors.invalid_account()        existing_tx = await self.get_active_transaction(order.id)        if existing_tx:            rejected = PaymeTransaction(                payme_id=ctx.payme_id,                order_id=order.id,                amount=ctx.amount,                create_time=ctx.time,                state=-1,                cancel_time=time_to_payme(),                reason=3,            )            self.db.add(rejected)            await self.db.commit()            raise Errors.unable_to_perform()        tx = PaymeTransaction(            payme_id=ctx.payme_id,            order_id=order.id,            amount=ctx.amount,            create_time=ctx.time,            state=1,        )        self.db.add(tx)        await self.db.execute(            update(Order)            .where(Order.id == order.id)            .values(payme_transaction_id=ctx.payme_id)        )        await self.db.commit()        return ctx.ok(transaction_id=tx.payme_id, create_time=tx.create_time)    async def perform_transaction(self, ctx: PerformTransactionCtx):        tx = await self.get_transaction(ctx.transaction_id)        if not tx:            raise Errors.transaction_not_found()        if tx.state == 2:            return ctx.ok(transaction_id=tx.payme_id, perform_time=tx.perform_time, state=2)        tx.state = 2        tx.perform_time = time_to_payme()        await self.db.execute(            update(Order)            .where(Order.id == tx.order_id)            .values(status=OrderStatus.PAID.value)        )        await self.db.commit()        return ctx.ok(transaction_id=tx.payme_id, perform_time=tx.perform_time, state=2)    async def cancel_transaction(self, ctx: CancelTransactionCtx):        tx = await self.get_transaction(ctx.transaction_id)        if not tx:            raise Errors.transaction_not_found()        if tx.state in (-1, -2):            return ctx.ok(                transaction=tx.payme_id,                cancel_time=tx.cancel_time,                state=tx.state,                reason=tx.reason,            )        tx.state = -2 if tx.state == 2 else -1        tx.cancel_time = time_to_payme()        tx.reason = ctx.reason        await self.db.execute(            update(Order)            .where(Order.id == tx.order_id)            .values(status=OrderStatus.CANCELLED.value)        )        await self.db.commit()        return ctx.ok(            transaction=tx.payme_id,            state=tx.state,            cancel_time=tx.cancel_time,            reason=tx.reason,        )    async def check_transaction(self, ctx: CheckTransactionCtx):        tx = await self.get_transaction(ctx.transaction_id)        if not tx:            raise Errors.transaction_not_found()        return ctx.ok(            state=tx.state,            create_time=tx.create_time,            perform_time=tx.perform_time,            cancel_time=tx.cancel_time,            reason=tx.reason,        )    async def get_statement(self, ctx: GetStatementCtx):        from_time = ctx.from_time        to_time = ctx.to_time        if from_time &gt; to_time:            from_time, to_time = to_time, from_time        txs = await self.get_transactions(from_time, to_time)        return ctx.ok(transactions=[            {                \"id\": tx.payme_id,                \"time\": tx.create_time,                \"amount\": tx.amount,                \"account\": {\"order_id\": tx.order_id},                \"state\": tx.state,                \"create_time\": tx.create_time,                \"perform_time\": tx.perform_time or 0,                \"cancel_time\": tx.cancel_time or 0,                \"reason\": tx.reason,            }            for tx in txs        ])<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u2014 \u0441\u0443\u043c\u043c\u0430 \u0432 Payme \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0432 \u0442\u0438\u0439\u0438\u043d\u0430\u0445 (1 \u0441\u0443\u043c = 100 \u0442\u0438\u0439\u0438\u043d),  \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0443\u043c\u043d\u043e\u0436\u0430\u0435\u043c <code>order.amount * 100<\/code>.  <\/p>\n<h3>\u0425\u0435\u043d\u0434\u043b\u0435\u0440\u044b  <\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0440\u043e\u0443\u0442\u0435\u0440 \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441. \u041a\u0430\u0436\u0434\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 Payme \u2014  \u044d\u0442\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440. Dependency injection \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u2014  \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0443\u0436\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u0430\u043a \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438:  <\/p>\n<pre><code># handlers\/payme.pyfrom aiopayme import Routerfrom aiopayme.types import *from sqlalchemy.ext.asyncio import AsyncSessionfrom services.payme import PaymeServicefrom deps import botrouter = Router()@router.check_perform_transaction()async def check_perform(ctx: CheckPerformTransactionCtx, db: AsyncSession):    return await PaymeService(db).check_perform(ctx)@router.create_transaction()async def create_transaction(ctx: CreateTransactionCtx, db: AsyncSession):    return await PaymeService(db).create_transaction(ctx)@router.perform_transaction()async def perform_transaction(ctx: PerformTransactionCtx, db: AsyncSession):    result = await PaymeService(db).perform_transaction(ctx)    tx = await PaymeService(db).get_transaction(ctx.transaction_id)    order = await PaymeService(db).get_order(tx.order_id)    await bot.send_message(        chat_id=order.telegram_id,        text=\"\u2705 \u041e\u043f\u043b\u0430\u0442\u0430 \u043f\u0440\u043e\u0448\u043b\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e.\"    )    return result@router.cancel_transaction()async def cancel_transaction(ctx: CancelTransactionCtx, db: AsyncSession):    return await PaymeService(db).cancel_transaction(ctx)@router.check_transaction()async def check_transaction(ctx: CheckTransactionCtx, db: AsyncSession):    return await PaymeService(db).check_transaction(ctx)@router.get_statement()async def get_statement(ctx: GetStatementCtx, db: AsyncSession):    return await PaymeService(db).get_statement(ctx)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>deps.py  <\/h3>\n<p>\u0417\u0434\u0435\u0441\u044c \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u2014 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u043e\u0442\u0430 \u0438 Payme:  <\/p>\n<pre><code>from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmakerfrom aiopayme import Paymefrom aiogram import Botengine = create_async_engine(\"sqlite+aiosqlite:\/\/\/.\/db.sqlite3\")SessionLocal = async_sessionmaker(engine, expire_on_commit=False)payme = Payme(    merchant_id=\"your_merchant_id\",    secret_key=your_secret_test_key,    sandbox=True,    echo=True,)bot = Bot(token=\"your_bot_token\")<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u0420\u043e\u0443\u0442\u0435\u0440\u044b  <\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0434\u0432\u0430 \u0440\u043e\u0443\u0442\u0435\u0440\u0430 \u2014 \u0434\u043b\u044f \u0432\u0435\u0431\u0445\u0443\u043a\u0430 Payme \u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0437\u0430\u043a\u0430\u0437\u0430:  <\/p>\n<pre><code># routers\/order.pyfrom fastapi import APIRouterfrom sqlalchemy import insertfrom pydantic import BaseModelfrom deps import SessionLocal, paymefrom models import Orderrouter = APIRouter()class OrderCreate(BaseModel):    telegram_id: int    amount: int@router.post(\"\/order\/create\")async def create_order(data: OrderCreate):    async with SessionLocal() as db:        result = await db.execute(            insert(Order).values(                telegram_id=data.telegram_id,                amount=data.amount            ).returning(Order.id)        )        order_id = result.scalar()        await db.commit()    pay_link = payme.generate_pay_link(        amount=data.amount,        account={            \"order_id\": order_id,            \"telegram_id\": data.telegram_id        }    )    return {\"order_id\": order_id, \"pay_link\": pay_link}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code># routers\/webhook.pyfrom fastapi import APIRouter, Requestfrom deps import paymerouter = APIRouter()@router.post(\"\/payme\")async def payme_webhook(request: Request):    data = await request.json()    result = await payme.handle(        data=data,        headers=dict(request.headers)    )    return result<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Payme \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u043e\u0434\u0438\u043d \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 <code>POST \/payme<\/code>.  \u041c\u0435\u0442\u043e\u0434 <code>handle<\/code> \u0441\u0430\u043c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0433\u043e \u0432 \u043d\u0443\u0436\u043d\u044b\u0439 \u0445\u0435\u043d\u0434\u043b\u0435\u0440.  <\/p>\n<h3>Telegram \u0431\u043e\u0442  <\/h3>\n<p>\u0411\u043e\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \/pay, \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0437\u0430\u043a\u0430\u0437 \u0447\u0435\u0440\u0435\u0437 API \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043e\u043f\u043b\u0430\u0442\u0443:  <\/p>\n<pre><code># bot\/main.pyimport asyncioimport httpxfrom aiogram import Dispatcherfrom aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButtonfrom aiogram.filters import Commandfrom deps import botdp = Dispatcher()def get_pay_link_btn(url: str) -&gt; InlineKeyboardMarkup:    return InlineKeyboardMarkup(        inline_keyboard=[            [InlineKeyboardButton(text=\"\u2705 \u041e\u043f\u043b\u0430\u0442\u0438\u0442\u044c\", url=url)]        ]    )@dp.message(Command(\"pay\"))async def cmd_pay(message: Message):    async with httpx.AsyncClient() as client:        response = await client.post(            \"http:\/\/localhost:8000\/order\/create\",            json={                \"telegram_id\": message.from_user.id,                \"amount\": 1000            }        )        data = response.json()        await message.answer(            \"\u041e\u043f\u043b\u0430\u0442\u0438\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u043e \u043a\u043d\u043e\u043f\u043a\u0435 \u043d\u0438\u0436\u0435\",            reply_markup=get_pay_link_btn(data[\"pay_link\"])        )async def main():    await dp.start_polling(bot)if __name__ == '__main__':    asyncio.run(main())<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u043e\u043f\u043b\u0430\u0442\u044b Payme \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 <code>perform_transaction<\/code> \u2014  \u0438 \u0431\u043e\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435.  <\/p>\n<h3>\u0410\u0434\u043c\u0438\u043d\u043a\u0430<\/h3>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043a\u0430\u0437\u0430\u043c\u0438 \u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c sqladmin: <\/p>\n<pre><code># admin\/admin.pyfrom sqladmin import ModelViewfrom models import Order, PaymeTransactionclass OrderAdmin(ModelView, model=Order):    name = \"Order\"    name_plural = \"Orders\"    column_list = \"__all__\"class PaymeTransactionAdmin(ModelView, model=PaymeTransaction):    name = \"Transaction\"    name_plural = \"Transactions\"    column_list = \"__all__\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0410\u0434\u043c\u0438\u043d\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <a href=\"http:\/\/localhost:8000\/admin%60\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:8000\/admin<\/a>.  <\/p>\n<h3>main.py  <\/h3>\n<p>\u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0451 \u0432\u043c\u0435\u0441\u0442\u0435 \u2014 FastAPI, Payme, \u0430\u0434\u043c\u0438\u043d\u043a\u0430:  <\/p>\n<pre><code># main.pyimport asynciofrom contextlib import asynccontextmanagerfrom fastapi import FastAPIfrom sqlalchemy.ext.asyncio import AsyncSessionfrom sqladmin import Adminimport uvicornfrom aiopayme import Dispatcherfrom models import Basefrom deps import engine, SessionLocal, paymefrom routers.order import router as order_routerfrom routers.webhook import router as webhook_routerfrom handlers.payme import router as payme_routerfrom admin.admin import OrderAdmin, PaymeTransactionAdmindp = Dispatcher()dp.include_router(payme_router)payme.setup(dp)payme.provide(AsyncSession, SessionLocal)@asynccontextmanagerasync def lifespan(app: FastAPI):    async with engine.begin() as conn:        await conn.run_sync(Base.metadata.create_all)    yield    await engine.dispose()app = FastAPI(lifespan=lifespan)app.include_router(order_router)app.include_router(webhook_router)admin = Admin(app, engine)admin.add_view(OrderAdmin)admin.add_view(PaymeTransactionAdmin)async def main():    config = uvicorn.Config(app, host=\"0.0.0.0\", port=8000)    server = uvicorn.Server(config)    await server.serve()if __name__ == '__main__':    asyncio.run(main())<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0411\u043e\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c: <\/p>\n<pre><code>python bot\/main.py   # Telegram botpython main.py # backend<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 <\/h3>\n<p>\u0442\u0443\u043d\u043d\u0435\u043b\u044c  Payme \u0434\u043e\u043b\u0436\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u0447\u0430\u0442\u044c\u0441\u044f \u0434\u043e \u0432\u0430\u0448\u0435\u0433\u043e \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430.  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0442\u0443\u043d\u043d\u0435\u043b\u044c \u2014 ngrok \u0438\u043b\u0438 cloudflared. <\/p>\n<pre><code>cloudflared tunnel --url http:\/\/0.0.0.0\/8000<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u0410\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u044f \u043a\u0430\u0441\u0441\u044b <\/h3>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0431\u043e\u0435\u0432\u044b\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0432 \u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u0435 Payme.  \u0412\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b (<code>CheckPerformTransaction<\/code>, <code>CreateTransaction<\/code>, <code>PerformTransaction<\/code> \u0438 \u0442.\u0434.)  \u0434\u043e\u043b\u0436\u043d\u044b \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b. <\/p>\n<p><strong>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435  <\/strong><\/p>\n<p>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0433\u043e\u0442\u043e\u0432\u0430! \u041f\u0435\u0440\u0435\u0434 \u0432\u044b\u0445\u043e\u0434\u043e\u043c \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435:  &#8212; \u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c <code>secret_key<\/code> \u043d\u0430 \u0431\u043e\u0435\u0432\u043e\u0439 <\/p>\n<pre><code>payme = Payme(    merchant_id=\"your_merchant_id\",    secret_key=\"your_secret_key\", # prod    sandbox=False,    echo=False)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u0423\u0434\u0430\u0447\u0438 \u0441 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0435\u0439! \ud83d\ude80  <\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1042466\/\">https:\/\/habr.com\/ru\/articles\/1042466\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043a\u0430\u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c Payme \u2014 \u043e\u0434\u043d\u0443 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043f\u043b\u0430\u0442\u0451\u0436\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c \u0423\u0437\u0431\u0435\u043a\u0438\u0441\u0442\u0430\u043d\u0430 \u2014 \u043a Telegram \u0431\u043e\u0442\u0443 \u043d\u0430 Python.  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 aiopayme \u2014 async-first \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0441 \u0440\u043e\u0443\u0442\u0435\u0440\u0430\u043c\u0438 \u0438 dependency injection \u043a\u0430\u043a \u0432 aiogram \u0438 FastAPI.  \u0412 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0430\u0431\u043e\u0447\u0443\u044e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e: \u0431\u043e\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \/pay, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u043f\u043b\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 Payme, \u0431\u043e\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u043e\u043f\u043b\u0430\u0442\u0435.  \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430  pip install aiopayme\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 aiopayme?  aiopayme \u2014 \u044d\u0442\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f Python \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u043f\u043b\u0430\u0442\u0451\u0436\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b Payme.  \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u2014 \u0440\u043e\u0443\u0442\u0435\u0440\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u0437\u043d\u0430\u043a\u043e\u043c\u0430\u044f \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u043a\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441 aiogram \u0438\u043b\u0438 FastAPI:from aiopayme import Routerrouter = Router()@router.check_perform_transaction()async def check_perform(ctx: CheckPerformTransactionCtx, db: AsyncSession): &#8230;\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u2014 httpx. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043d\u0435 \u043d\u0430\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 ORM, \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0438\u043b\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.  \u041c\u043e\u0434\u0435\u043b\u0438  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u2014 \u0437\u0430\u043a\u0430\u0437 \u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e Payme. # models\/order.pyimport enumfrom sqlalchemy import Column, BigInteger, Integer, Stringfrom sqlalchemy.orm import DeclarativeBaseclass Base(DeclarativeBase):    passclass OrderStatus(enum.Enum):    PENDING = &#171;pending&#187;    PAID = &#171;paid&#187;    CANCELED = &#171;canceled&#187;class Order(Base):    __tablename__ = &#171;orders&#187;    id = Column(Integer, primary_key=True)    telegram_id = Column(BigInteger, nullable=False)    amount = Column(BigInteger, nullable=False)    status = Column(String, default=OrderStatus.PENDING.value)    payme_transaction_id = Column(String, nullable=True)# models\/payme.pyfrom sqlalchemy import Column, Integer, String, BigIntegerfrom models.order import Baseclass PaymeTransaction(Base):    __tablename__ = &#171;payme_transactions&#187;    id = Column(Integer, primary_key=True)    payme_id = Column(String, unique=True, nullable=False)    order_id = Column(Integer, nullable=True)    state = Column(Integer, default=1)    amount = Column(BigInteger, nullable=False)    create_time = Column(BigInteger, nullable=False)    perform_time = Column(BigInteger, default=0)    cancel_time = Column(BigInteger, default=0)    reason = Column(Integer, nullable=True)PaymeService  \u0412\u044b\u043d\u0435\u0441\u0435\u043c \u0432\u0441\u044e \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441. \u042d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u044b \u0447\u0438\u0441\u0442\u044b\u043c\u0438  \u0438 \u043b\u043e\u0433\u0438\u043a\u0443 \u043b\u0435\u0433\u043a\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0439. \u0421\u043e\u0437\u0434\u0430\u0451\u043c services\/payme.py:  # services\/payme.pyfrom sqlalchemy import select, updatefrom sqlalchemy.ext.asyncio import AsyncSessionfrom aiopayme.exceptions import Errorsfrom aiopayme.utils import time_to_paymefrom aiopayme.types import (    CheckPerformTransactionCtx,    CreateTransactionCtx,    PerformTransactionCtx,    CancelTransactionCtx,    CheckTransactionCtx,    GetStatementCtx,)from models import OrderStatus, Order, PaymeTransactionclass PaymeService:    def __init__(self, db: AsyncSession):        self.db = db    async def get_order(self, order_id) -&gt; Order | None:        return await self.db.scalar(            select(Order).where(Order.id == int(order_id))        )    async def get_transaction(self, payme_id: str) -&gt; PaymeTransaction | None:        return await self.db.scalar(            select(PaymeTransaction).where(PaymeTransaction.payme_id == payme_id)        )    async def get_active_transaction(self, order_id: int) -&gt; PaymeTransaction | None:        return await self.db.scalar(            select(PaymeTransaction).where(                PaymeTransaction.order_id == order_id,                PaymeTransaction.state == 1,            )        )    async def get_transactions(self, from_time: int, to_time: int):        return (await self.db.scalars(            select(PaymeTransaction).where(                PaymeTransaction.create_time &gt;= from_time,                PaymeTransaction.create_time &lt;= to_time,            )        )).all()    async def check_perform(self, ctx: CheckPerformTransactionCtx):        order = await self.get_order(ctx.account.order_id)        if not order:            raise Errors.invalid_account()        if order.amount * 100 != ctx.amount:            raise Errors.invalid_amount()        return ctx.ok(allow=True)    async def create_transaction(self, ctx: CreateTransactionCtx):        tx = await self.get_transaction(ctx.payme_id)        order = await self.get_order(ctx.account.order_id)        if not order:            raise Errors.invalid_account()        if order.amount * 100 != ctx.amount:            raise Errors.invalid_amount()        if tx:            if tx.state == -1:                raise Errors.unable_to_perform()            return ctx.ok(transaction_id=tx.payme_id, create_time=tx.create_time)        if order.status == OrderStatus.PAID:            raise Errors.invalid_account()        existing_tx = await self.get_active_transaction(order.id)        if existing_tx:            rejected = PaymeTransaction(                payme_id=ctx.payme_id,                order_id=order.id,                amount=ctx.amount,                create_time=ctx.time,                state=-1,                cancel_time=time_to_payme(),                reason=3,            )            self.db.add(rejected)            await self.db.commit()            raise Errors.unable_to_perform()        tx = PaymeTransaction(            payme_id=ctx.payme_id,            order_id=order.id,            amount=ctx.amount,            create_time=ctx.time,            state=1,        )        self.db.add(tx)        await self.db.execute(            update(Order)            .where(Order.id == order.id)            .values(payme_transaction_id=ctx.payme_id)        )        await self.db.commit()        return ctx.ok(transaction_id=tx.payme_id, create_time=tx.create_time)    async def perform_transaction(self, ctx: PerformTransactionCtx):        tx = await self.get_transaction(ctx.transaction_id)        if not tx:            raise Errors.transaction_not_found()        if tx.state == 2:            return ctx.ok(transaction_id=tx.payme_id, perform_time=tx.perform_time, state=2)        tx.state = 2        tx.perform_time = time_to_payme()        await self.db.execute(            update(Order)            .where(Order.id == tx.order_id)            .values(status=OrderStatus.PAID.value)        )        await self.db.commit()        return ctx.ok(transaction_id=tx.payme_id, perform_time=tx.perform_time, state=2)    async def cancel_transaction(self, ctx: CancelTransactionCtx):        tx = await self.get_transaction(ctx.transaction_id)        if not tx:            raise Errors.transaction_not_found()        if tx.state in (-1, -2):            return ctx.ok(                transaction=tx.payme_id,                cancel_time=tx.cancel_time,                state=tx.state,                reason=tx.reason,            )        tx.state = -2 if tx.state == 2 else -1        tx.cancel_time = time_to_payme()        tx.reason = ctx.reason        await self.db.execute(            update(Order)            .where(Order.id == tx.order_id)            .values(status=OrderStatus.CANCELLED.value)        )        await self.db.commit()        return ctx.ok(            transaction=tx.payme_id,            state=tx.state,            cancel_time=tx.cancel_time,            reason=tx.reason,        )    async def check_transaction(self, ctx: CheckTransactionCtx):        tx = await self.get_transaction(ctx.transaction_id)        if not tx:            raise Errors.transaction_not_found()        return ctx.ok(            state=tx.state,            create_time=tx.create_time,            perform_time=tx.perform_time,            cancel_time=tx.cancel_time,            reason=tx.reason,        )    async def get_statement(self, ctx: GetStatementCtx):        from_time = ctx.from_time        to_time = ctx.to_time        if from_time &gt; to_time:            from_time, to_time = to_time, from_time        txs = await self.get_transactions(from_time, to_time)        return ctx.ok(transactions=[            {                &#171;id&#187;: tx.payme_id,                &#171;time&#187;: tx.create_time,                &#171;amount&#187;: tx.amount,                &#171;account&#187;: {&#171;order_id&#187;: tx.order_id},                &#171;state&#187;: tx.state,                &#171;create_time&#187;: tx.create_time,                &#171;perform_time&#187;: tx.perform_time or 0,                &#171;cancel_time&#187;: tx.cancel_time or 0,                &#171;reason&#187;: tx.reason,            }            for tx in txs        ])\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u2014 \u0441\u0443\u043c\u043c\u0430 \u0432 Payme \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0432 \u0442\u0438\u0439\u0438\u043d\u0430\u0445 (1 \u0441\u0443\u043c = 100 \u0442\u0438\u0439\u0438\u043d),  \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0443\u043c\u043d\u043e\u0436\u0430\u0435\u043c order.amount * 100.  \u0425\u0435\u043d\u0434\u043b\u0435\u0440\u044b  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0440\u043e\u0443\u0442\u0435\u0440 \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441. \u041a\u0430\u0436\u0434\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 Payme \u2014  \u044d\u0442\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440. Dependency injection \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u2014  \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0443\u0436\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u0430\u043a \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438:  # handlers\/payme.pyfrom aiopayme import Routerfrom aiopayme.types import *from sqlalchemy.ext.asyncio import AsyncSessionfrom services.payme import PaymeServicefrom deps import botrouter = Router()@router.check_perform_transaction()async def check_perform(ctx: CheckPerformTransactionCtx, db: AsyncSession):    return await PaymeService(db).check_perform(ctx)@router.create_transaction()async def create_transaction(ctx: CreateTransactionCtx, db: AsyncSession):    return await PaymeService(db).create_transaction(ctx)@router.perform_transaction()async def perform_transaction(ctx: PerformTransactionCtx, db: AsyncSession):    result = await PaymeService(db).perform_transaction(ctx)    tx = await PaymeService(db).get_transaction(ctx.transaction_id)    order = await PaymeService(db).get_order(tx.order_id)    await bot.send_message(        chat_id=order.telegram_id,        text=&#187;\u2705 \u041e\u043f\u043b\u0430\u0442\u0430 \u043f\u0440\u043e\u0448\u043b\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e.&#187;    )    return result@router.cancel_transaction()async def cancel_transaction(ctx: CancelTransactionCtx, db: AsyncSession):    return await PaymeService(db).cancel_transaction(ctx)@router.check_transaction()async def check_transaction(ctx: CheckTransactionCtx, db: AsyncSession):    return await PaymeService(db).check_transaction(ctx)@router.get_statement()async def get_statement(ctx: GetStatementCtx, db: AsyncSession):    return await PaymeService(db).get_statement(ctx)deps.py  \u0417\u0434\u0435\u0441\u044c&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-482005","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/482005","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=482005"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/482005\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=482005"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=482005"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=482005"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}