Merge pull request #21 from Vladless/youkassa
Доработка платежей, уведомления и переработка интерфейса
This commit is contained in:
+1
-1
@@ -48,7 +48,7 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery):
|
||||
|
||||
# Создаем клавиатуру с кнопками
|
||||
inline_keyboard = types.InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||
response_message = "<b>Выберите ключ для просмотра информации:</b>"
|
||||
response_message = "<b>Выберите устройство:</b>"
|
||||
|
||||
# Редактируем сообщение с клавиатурой
|
||||
await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=inline_keyboard, parse_mode="HTML")
|
||||
|
||||
+48
-55
@@ -9,7 +9,7 @@ import logging
|
||||
import uuid
|
||||
|
||||
from bot import bot
|
||||
from config import ADMIN_ID, DATABASE_URL, YOOKASSA_SECRET_KEY, YOOKASSA_SHOP_ID
|
||||
from config import YOOKASSA_SECRET_KEY, YOOKASSA_SHOP_ID
|
||||
from database import (add_connection, check_connection_exists, get_balance,
|
||||
get_key_count, update_balance)
|
||||
from handlers.profile import process_callback_view_profile
|
||||
@@ -26,7 +26,6 @@ logging.debug(f"Account ID: {YOOKASSA_SHOP_ID}")
|
||||
logging.debug(f"Secret Key: {YOOKASSA_SECRET_KEY}")
|
||||
|
||||
class ReplenishBalanceState(StatesGroup):
|
||||
choosing_transfer_method = State()
|
||||
choosing_amount = State()
|
||||
waiting_for_payment_confirmation = State()
|
||||
|
||||
@@ -62,50 +61,24 @@ async def process_callback_replenish_balance(callback_query: types.CallbackQuery
|
||||
if not exists:
|
||||
await add_connection(tg_id, balance=0.0, trial=0)
|
||||
|
||||
await state.set_state(ReplenishBalanceState.choosing_transfer_method)
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='По реквизитам', callback_data='transfer_method_requisites')],
|
||||
# Переходим сразу к выбору суммы пополнения
|
||||
amount_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='100 RUB', callback_data='amount_100'), InlineKeyboardButton(text='300 RUB', callback_data='amount_300')],
|
||||
[InlineKeyboardButton(text='600 RUB', callback_data='amount_600'), InlineKeyboardButton(text='1000 RUB', callback_data='amount_1000')],
|
||||
[InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')]
|
||||
])
|
||||
|
||||
await callback_query.message.edit_text(
|
||||
text="Выберите метод перевода:",
|
||||
reply_markup=keyboard
|
||||
text="Выберите сумму пополнения:",
|
||||
reply_markup=amount_keyboard
|
||||
)
|
||||
await state.set_state(ReplenishBalanceState.choosing_amount)
|
||||
await callback_query.answer()
|
||||
|
||||
@router.callback_query(lambda c: c.data == 'back_to_profile')
|
||||
async def back_to_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
await process_callback_view_profile(callback_query, state)
|
||||
|
||||
@router.callback_query(lambda c: c.data.startswith('transfer_method_'))
|
||||
async def process_transfer_method_selection(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
data = callback_query.data.split('_', 2)
|
||||
|
||||
if len(data) != 3:
|
||||
await send_message_with_deletion(callback_query.from_user.id, "Неверные данные для выбора метода перевода.", state=state, message_key='transfer_method_error_message_id')
|
||||
return
|
||||
|
||||
transfer_method = data[2]
|
||||
|
||||
if transfer_method == 'requisites':
|
||||
amount_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='100 RUB', callback_data='amount_100'), InlineKeyboardButton(text='300 RUB', callback_data='amount_300')],
|
||||
[InlineKeyboardButton(text='600 RUB', callback_data='amount_600'), InlineKeyboardButton(text='1000 RUB', callback_data='amount_1000')],
|
||||
[InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')]
|
||||
])
|
||||
|
||||
await callback_query.message.edit_text(
|
||||
text="Выберите сумму пополнения:",
|
||||
reply_markup=amount_keyboard
|
||||
)
|
||||
await state.update_data(transfer_method=transfer_method)
|
||||
await state.set_state(ReplenishBalanceState.choosing_amount)
|
||||
|
||||
else:
|
||||
await send_message_with_deletion(callback_query.from_user.id, "Неверный метод перевода.", state=state, message_key='transfer_method_error_message_id')
|
||||
return
|
||||
|
||||
@router.callback_query(lambda c: c.data.startswith('amount_'))
|
||||
async def process_amount_selection(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
data = callback_query.data.split('_', 1)
|
||||
@@ -125,9 +98,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
||||
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation)
|
||||
|
||||
state_data = await state.get_data()
|
||||
transfer_method = state_data.get('transfer_method')
|
||||
|
||||
# Получаем имя клиента из Telegram профиля
|
||||
customer_name = callback_query.from_user.full_name
|
||||
customer_id = callback_query.from_user.id
|
||||
|
||||
@@ -139,59 +109,82 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
||||
},
|
||||
"confirmation": {
|
||||
"type": "redirect",
|
||||
"return_url": "https://pocomacho.ru/"
|
||||
"return_url": "https://pocomacho.ru/" # Укажите реальный URL для возврата
|
||||
},
|
||||
"capture": True,
|
||||
"description": "Пополнение баланса",
|
||||
"receipt": {
|
||||
"customer": {
|
||||
"full_name": customer_name, # Имя клиента
|
||||
"email": "client@example.com", # Можно добавить email, если у вас есть
|
||||
"phone": "79000000000" # Телефон клиента, если есть
|
||||
"full_name": customer_name,
|
||||
"email": "client@example.com",
|
||||
"phone": "79000000000"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"description": "Пополнение баланса", # Описание услуги
|
||||
"description": "Пополнение баланса",
|
||||
"quantity": "1.00",
|
||||
"amount": {
|
||||
"value": str(amount),
|
||||
"currency": "RUB"
|
||||
},
|
||||
"vat_code": 6 # Код налога (для самозанятых 6)
|
||||
"vat_code": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"user_id": customer_id # ID пользователя
|
||||
"user_id": customer_id
|
||||
}
|
||||
}, uuid.uuid4()) # Уникальный идентификатор для транзакции
|
||||
}, uuid.uuid4())
|
||||
|
||||
# Отправляем пользователю ссылку для оплаты
|
||||
if payment['status'] == 'pending':
|
||||
await send_message_with_deletion(
|
||||
callback_query.from_user.id,
|
||||
f"Перейдите по ссылке для оплаты: {payment['confirmation']['confirmation_url']}",
|
||||
state=state
|
||||
payment_url = payment['confirmation']['confirmation_url']
|
||||
|
||||
confirm_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='Пополнить', url=payment_url)],
|
||||
[InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')]
|
||||
])
|
||||
|
||||
await callback_query.message.edit_text(
|
||||
text=f"Вы выбрали пополнение на {amount} рублей.",
|
||||
reply_markup=confirm_keyboard
|
||||
)
|
||||
else:
|
||||
await send_message_with_deletion(callback_query.from_user.id, "Ошибка при создании платежа.", state=state)
|
||||
|
||||
await callback_query.answer()
|
||||
|
||||
async def send_payment_success_notification(user_id: int, amount: float):
|
||||
try:
|
||||
profile_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='Перейти в профиль', callback_data='view_profile')]
|
||||
])
|
||||
|
||||
await bot.send_message(
|
||||
chat_id=user_id,
|
||||
text=f"Ваш баланс успешно пополнен на {amount} рублей. Спасибо за оплату!",
|
||||
reply_markup=profile_keyboard
|
||||
)
|
||||
except Exception as e:
|
||||
logging.error(f"Ошибка при отправке уведомления пользователю {user_id}: {e}")
|
||||
|
||||
async def payment_webhook(request):
|
||||
event = await request.json()
|
||||
|
||||
logging.debug(f"Webhook event received: {event}")
|
||||
|
||||
# Обработка успешного платежа
|
||||
if event['event'] == 'payment.succeeded':
|
||||
user_id_str = event['object']['metadata']['user_id']
|
||||
amount_str = event['object']['amount']['value']
|
||||
|
||||
try:
|
||||
user_id = int(user_id_str) # Конвертируем user_id в int
|
||||
amount = float(amount_str) # Конвертируем сумму из строки в float
|
||||
user_id = int(user_id_str)
|
||||
amount = float(amount_str)
|
||||
|
||||
logging.debug(f"Payment succeeded for user_id: {user_id}, amount: {amount}")
|
||||
await update_balance(user_id, amount) # Передаем число в функцию обновления баланса
|
||||
await update_balance(user_id, amount)
|
||||
|
||||
await send_payment_success_notification(user_id, amount)
|
||||
|
||||
except ValueError as e:
|
||||
logging.error(f"Ошибка конвертации user_id или amount: {e}")
|
||||
return web.Response(status=400)
|
||||
|
||||
+3
-4
@@ -31,12 +31,12 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
|
||||
f"<b>Профиль: {username}</b>\n\n"
|
||||
f"🔹 <b>ID:</b> {tg_id}\n"
|
||||
f"🔹 <b>Баланс:</b> {balance} RUB\n"
|
||||
f"🔹 <b>Количество ключей:</b> {key_count}\n"
|
||||
f"🔹 <b>К-во устройств:</b> {key_count}\n" # Изменили текст на "К-во устройств"
|
||||
)
|
||||
|
||||
# Кнопки для действий в профиле с добавленными смайликами
|
||||
button_create_key = InlineKeyboardButton(text='🔑 Создать ключ', callback_data='create_key')
|
||||
button_view_keys = InlineKeyboardButton(text='🔐 Мои ключи', callback_data='view_keys')
|
||||
button_create_key = InlineKeyboardButton(text='➕ Устройство', callback_data='create_key')
|
||||
button_view_keys = InlineKeyboardButton(text='📱 Мои устройства', callback_data='view_keys')
|
||||
button_replenish_balance = InlineKeyboardButton(text='💳 Пополнить баланс', callback_data='replenish_balance')
|
||||
button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_menu') # Добавляем кнопку "Назад"
|
||||
|
||||
@@ -67,4 +67,3 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
|
||||
@router.callback_query(lambda c: c.data == 'view_profile')
|
||||
async def view_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
await process_callback_view_profile(callback_query, state)
|
||||
|
||||
|
||||
+2
-41
@@ -8,7 +8,7 @@ from aiogram.types import (BufferedInputFile, CallbackQuery,
|
||||
InlineKeyboardButton, InlineKeyboardMarkup, Message)
|
||||
|
||||
from bot import bot
|
||||
from config import ADMIN_ID, CHANNEL_URL
|
||||
from config import ADMIN_ID, CHANNEL_URL, SUPPORT_CHAT_URL # Добавьте SUPPORT_CHAT_URL
|
||||
|
||||
router = Router()
|
||||
|
||||
@@ -35,7 +35,7 @@ async def send_welcome_message(chat_id: int):
|
||||
inline_keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='👤 Мой профиль', callback_data='view_profile')],
|
||||
[InlineKeyboardButton(text='🔒 О VPN', callback_data='about_vpn')],
|
||||
[InlineKeyboardButton(text='📝 Обратная связь', callback_data='feedback')],
|
||||
[InlineKeyboardButton(text='📞 Поддержка', url=SUPPORT_CHAT_URL)], # Изменили на кнопку Поддержка
|
||||
[InlineKeyboardButton(text='📢 Наш канал', url=CHANNEL_URL)]
|
||||
])
|
||||
|
||||
@@ -83,42 +83,3 @@ async def handle_back_to_menu(callback_query: CallbackQuery):
|
||||
# Отправляем приветственное сообщение
|
||||
await send_welcome_message(callback_query.from_user.id)
|
||||
await callback_query.answer()
|
||||
|
||||
@router.callback_query(lambda c: c.data == 'feedback')
|
||||
async def handle_feedback(callback_query: CallbackQuery, state: FSMContext):
|
||||
# Удаляем сообщение главного меню
|
||||
await callback_query.message.delete()
|
||||
|
||||
feedback_text = "Напишите нам, если у вас возникли трудности с подключением, есть отзыв или предложение. @pocomacho"
|
||||
|
||||
button_back = InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_menu')
|
||||
inline_keyboard_back = InlineKeyboardMarkup(inline_keyboard=[[button_back]])
|
||||
|
||||
await callback_query.message.answer(
|
||||
feedback_text,
|
||||
parse_mode='Markdown',
|
||||
reply_markup=inline_keyboard_back
|
||||
)
|
||||
|
||||
await state.set_state(FeedbackState.waiting_for_feedback)
|
||||
await state.update_data(user_id=callback_query.from_user.id)
|
||||
await callback_query.answer()
|
||||
|
||||
@router.message(FeedbackState.waiting_for_feedback)
|
||||
async def receive_feedback(message: types.Message, state: FSMContext):
|
||||
user_data = await state.get_data()
|
||||
user_id = user_data.get('user_id')
|
||||
|
||||
feedback_message = (
|
||||
f"Обратная связь от пользователя {user_id}:\n\n"
|
||||
f"{message.text}"
|
||||
)
|
||||
|
||||
try:
|
||||
await bot.send_message(ADMIN_ID, feedback_message)
|
||||
await message.answer("Спасибо за ваше сообщение! Мы свяжемся с вами, если это будет необходимо.")
|
||||
except Exception as e:
|
||||
await message.answer("Произошла ошибка при отправке вашего сообщения.")
|
||||
print(f"Ошибка при отправке обратной связи: {e}") # Логирование ошибок
|
||||
|
||||
await state.clear()
|
||||
|
||||
+2
-1
@@ -208,7 +208,8 @@ async def handle_key_name_input(message: Message, state: FSMContext):
|
||||
key_message = (
|
||||
"✅ Ключ успешно создан:\n"
|
||||
f"<pre>{connection_link}</pre>\n\n"
|
||||
f"{remaining_time_message}"
|
||||
f"{remaining_time_message}\n\n"
|
||||
"<i>Добавьте ключ в приложение по инструкции ниже:</i>"
|
||||
)
|
||||
|
||||
await message.bot.send_message(tg_id, key_message, parse_mode="HTML", reply_markup=keyboard)
|
||||
|
||||
Reference in New Issue
Block a user