first commit
This commit is contained in:
167
bot/handlers/start.py
Normal file
167
bot/handlers/start.py
Normal file
@@ -0,0 +1,167 @@
|
||||
# Aiogram
|
||||
import aiogram.types as types
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.filters import CommandObject, CommandStart, StateFilter
|
||||
from aiogram import Router
|
||||
|
||||
# Utils
|
||||
from utils.text_tools import to_html
|
||||
from utils.amount_parser import format_rub_amount
|
||||
|
||||
# Const
|
||||
from create_bot import orm
|
||||
from services.wata import WataAPIError, WataClient
|
||||
|
||||
# States
|
||||
from states.client_states import MainStates
|
||||
|
||||
# Another
|
||||
from datetime import datetime, timezone
|
||||
import logging
|
||||
|
||||
|
||||
# Init
|
||||
start_router = Router()
|
||||
logger = logging.getLogger(__name__)
|
||||
wata_client = WataClient()
|
||||
|
||||
|
||||
@start_router.message(CommandStart(), StateFilter("*"))
|
||||
async def cmd_start(
|
||||
message: types.Message, state: FSMContext, command: CommandObject | None = None
|
||||
):
|
||||
|
||||
if message.chat.type != "private":
|
||||
return
|
||||
|
||||
await register_user(message)
|
||||
|
||||
command_args = command.args if command else None
|
||||
if command_args and command_args.startswith("payment_failed_"):
|
||||
order_id = command_args.removeprefix("payment_failed_")
|
||||
await show_payment_result(message, state, order_id)
|
||||
return
|
||||
|
||||
if command_args and command_args.startswith("payment_"):
|
||||
order_id = command_args.removeprefix("payment_")
|
||||
await show_payment_result(message, state, order_id)
|
||||
return
|
||||
|
||||
await state.set_state(MainStates.waiting_amount)
|
||||
await message.answer(
|
||||
text=(
|
||||
"Для продолжения работы укажите сумму оплаты в рублях, "
|
||||
"и я отправлю ссылку для безопасной оплаты.\n\n"
|
||||
"Отправьте сумму сообщением."
|
||||
),
|
||||
reply_markup=types.ReplyKeyboardRemove(),
|
||||
)
|
||||
|
||||
|
||||
async def register_user(message: types.Message) -> None:
|
||||
user_id = message.from_user.id
|
||||
username = (
|
||||
"@" + message.from_user.username
|
||||
if message.from_user.username is not None
|
||||
else None
|
||||
)
|
||||
fullname = to_html(message.from_user.full_name)
|
||||
|
||||
await orm.create_user(
|
||||
user_id=user_id,
|
||||
username=username,
|
||||
fullname=fullname,
|
||||
register_date=datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
|
||||
async def show_payment_result(
|
||||
message: types.Message, state: FSMContext, order_id: str
|
||||
) -> None:
|
||||
payment = await orm.get_payment_by_order_id(order_id)
|
||||
if payment is None:
|
||||
await state.set_state(MainStates.waiting_amount)
|
||||
await message.answer(
|
||||
text=(
|
||||
"Платёж не найден.\n\n"
|
||||
"Отправьте сумму сообщением, чтобы создать новую ссылку."
|
||||
),
|
||||
reply_markup=types.ReplyKeyboardRemove(),
|
||||
)
|
||||
return
|
||||
|
||||
if payment.status not in {"paid", "declined"}:
|
||||
await sync_payment_status(order_id)
|
||||
payment = await orm.get_payment_by_order_id(order_id)
|
||||
|
||||
await state.set_state(MainStates.main)
|
||||
|
||||
if payment.status == "paid":
|
||||
await message.answer(
|
||||
text=(
|
||||
f"Спасибо за оплату!\n\n"
|
||||
f"Платёж на сумму {format_rub_amount(payment.amount)} подтверждён."
|
||||
),
|
||||
reply_markup=types.ReplyKeyboardRemove(),
|
||||
)
|
||||
return
|
||||
|
||||
if payment.status == "declined":
|
||||
error_text = ""
|
||||
if payment.error_description:
|
||||
error_text = f"\nПричина: {payment.error_description}"
|
||||
|
||||
await message.answer(
|
||||
text=(
|
||||
"Оплата не была подтверждена платёжным сервисом."
|
||||
f"{error_text}\n\n"
|
||||
"Отправьте новую сумму сообщением, чтобы попробовать ещё раз."
|
||||
),
|
||||
reply_markup=types.ReplyKeyboardRemove(),
|
||||
)
|
||||
return
|
||||
|
||||
await message.answer(
|
||||
text=(
|
||||
"Платёж ещё обрабатывается платёжным сервисом. "
|
||||
"Если вы уже оплатили, подождите несколько секунд и снова откройте бота."
|
||||
),
|
||||
reply_markup=types.ReplyKeyboardRemove(),
|
||||
)
|
||||
|
||||
|
||||
async def sync_payment_status(order_id: str) -> None:
|
||||
try:
|
||||
transaction = await wata_client.find_transaction_by_order_id(order_id)
|
||||
except WataAPIError:
|
||||
logger.exception("WATA returned an API error while syncing order %s", order_id)
|
||||
return
|
||||
except Exception:
|
||||
logger.exception("Unexpected error while syncing order %s", order_id)
|
||||
return
|
||||
|
||||
if transaction is None:
|
||||
return
|
||||
|
||||
paid_at = None
|
||||
if transaction.payment_time:
|
||||
paid_at = datetime.fromisoformat(
|
||||
transaction.payment_time.strip().replace("Z", "+00:00")
|
||||
)
|
||||
|
||||
local_status = "pending"
|
||||
if transaction.status == "Paid":
|
||||
local_status = "paid"
|
||||
elif transaction.status == "Declined":
|
||||
local_status = "declined"
|
||||
|
||||
await orm.update_payment_status(
|
||||
order_id=order_id,
|
||||
status=local_status,
|
||||
transaction_status=transaction.status,
|
||||
transaction_id=transaction.id,
|
||||
error_code=transaction.error_code,
|
||||
error_description=transaction.error_description,
|
||||
updated_at=datetime.now(timezone.utc),
|
||||
paid_at=paid_at,
|
||||
)
|
||||
Reference in New Issue
Block a user