Merge pull request #21 from Vladless/youkassa

Доработка платежей, уведомления и переработка интерфейса
This commit is contained in:
Vladislav Lisitsyn
2024-10-02 01:13:35 +03:00
committed by GitHub
5 changed files with 56 additions and 102 deletions
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)