работающая оплата с подтверждением после перевода
This commit is contained in:
@@ -8,7 +8,7 @@ storage = MemoryStorage()
|
||||
dp = Dispatcher(bot=bot, storage=storage)
|
||||
router = Router()
|
||||
|
||||
from handlers import start, profile, keys, stats, expiry, balance
|
||||
from handlers import start, profile, keys, stats, expiry, balance, pay
|
||||
from key_management import router as key_management_router
|
||||
|
||||
|
||||
@@ -21,5 +21,7 @@ dp.include_router(expiry.router)
|
||||
dp.include_router(balance.router)
|
||||
dp.include_router(key_management_router)
|
||||
|
||||
|
||||
|
||||
async def on_startup(dispatcher: Dispatcher):
|
||||
await login_with_credentials()
|
||||
|
||||
@@ -81,3 +81,12 @@ async def get_balance(tg_id: int) -> str:
|
||||
async with db.execute("SELECT balance FROM connections WHERE tg_id = ?", (tg_id,)) as cursor:
|
||||
record = await cursor.fetchone()
|
||||
return record[0] if record else "Неизвестно"
|
||||
|
||||
async def update_balance(tg_id: int, amount: float):
|
||||
async with aiosqlite.connect(DATABASE_PATH) as db:
|
||||
await db.execute('''
|
||||
UPDATE connections
|
||||
SET balance = balance + ?
|
||||
WHERE tg_id = ?
|
||||
''', (amount, tg_id))
|
||||
await db.commit()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+128
-15
@@ -1,30 +1,35 @@
|
||||
from aiogram import types, Router
|
||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from database import get_active_key_email, get_balance
|
||||
from aiogram import Bot, Dispatcher, Router, types
|
||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from datetime import datetime
|
||||
import aiosqlite
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from config import DATABASE_PATH
|
||||
from config import DATABASE_PATH, ADMIN_ID
|
||||
from database import get_balance, update_balance, has_active_key
|
||||
from bot import bot
|
||||
|
||||
router = Router()
|
||||
|
||||
class ReplenishBalanceState(StatesGroup):
|
||||
choosing_transfer_method = State()
|
||||
waiting_for_admin_confirmation = State()
|
||||
|
||||
@router.callback_query(lambda c: c.data == 'view_profile')
|
||||
async def process_callback_view_profile(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
tg_id = callback_query.from_user.id
|
||||
username = callback_query.from_user.username
|
||||
|
||||
try:
|
||||
email = await get_active_key_email(tg_id)
|
||||
# Получаем активный ключ
|
||||
email = await has_active_key(tg_id)
|
||||
if email:
|
||||
async with aiosqlite.connect(DATABASE_PATH) as db:
|
||||
async with db.execute("SELECT expiry_time FROM connections WHERE tg_id = ? AND expiry_time > ?",
|
||||
(tg_id, int(datetime.utcnow().timestamp() * 1000))) as cursor:
|
||||
async with db.execute(
|
||||
"SELECT expiry_time FROM connections WHERE tg_id = ? AND expiry_time > ?",
|
||||
(tg_id, int(datetime.utcnow().timestamp() * 1000))
|
||||
) as cursor:
|
||||
record = await cursor.fetchone()
|
||||
if record:
|
||||
expiry_time = record[0]
|
||||
expiry_date = datetime.utcfromtimestamp(expiry_time / 1000).strftime("%Y-%m-%d %H:%M:%S")
|
||||
else:
|
||||
expiry_date = "Неизвестно"
|
||||
expiry_date = "Неизвестно" if record is None else datetime.utcfromtimestamp(record[0] / 1000).strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
balance = await get_balance(tg_id)
|
||||
profile_message = (
|
||||
@@ -36,9 +41,10 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
|
||||
)
|
||||
|
||||
button_view_keys = InlineKeyboardButton(text='Мои ключи', callback_data='view_keys')
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[[button_view_keys]])
|
||||
button_replenish_balance = InlineKeyboardButton(text='Пополнить баланс', callback_data='replenish_balance')
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[[button_view_keys], [button_replenish_balance]])
|
||||
|
||||
profile_message += "Вы можете просмотреть ваши ключи ниже:"
|
||||
profile_message += "Вы можете просмотреть ваши ключи или пополнить баланс ниже:"
|
||||
else:
|
||||
profile_message = "У вас нет активных ключей."
|
||||
keyboard = None
|
||||
@@ -47,5 +53,112 @@ async def process_callback_view_profile(callback_query: types.CallbackQuery, sta
|
||||
profile_message = f"Ошибка при получении данных профиля: {e}"
|
||||
keyboard = None
|
||||
|
||||
# Отправляем сообщение с клавиатурой внизу
|
||||
await callback_query.message.reply(profile_message, reply_markup=keyboard)
|
||||
await callback_query.answer()
|
||||
|
||||
|
||||
@router.callback_query(lambda c: c.data == 'replenish_balance')
|
||||
async def process_callback_replenish_balance(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
await state.set_state(ReplenishBalanceState.choosing_transfer_method)
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='По реквизитам', callback_data='transfer_method_requisites')],
|
||||
[InlineKeyboardButton(text='По СБП', callback_data='transfer_method_sbp')]
|
||||
])
|
||||
await callback_query.message.answer("Выберите метод перевода:", reply_markup=keyboard)
|
||||
await callback_query.answer()
|
||||
|
||||
@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 callback_query.answer("Неверные данные для выбора метода перевода.")
|
||||
return
|
||||
|
||||
transfer_method = data[2] # 'requisites' или 'sbp'
|
||||
amount = 100 # Можно заменить на 300, если нужно
|
||||
user_id = callback_query.from_user.id
|
||||
|
||||
# Сохраняем данные в состояние
|
||||
await state.update_data(transfer_method=transfer_method, amount=amount, user_id=user_id)
|
||||
|
||||
# Выводим состояние для отладки
|
||||
state_data = await state.get_data()
|
||||
print("Сохраненные данные состояния:", state_data)
|
||||
|
||||
# Отправляем запрос на подтверждение администратору
|
||||
admin_message = (
|
||||
f"Запрос на пополнение баланса:\n"
|
||||
f"Метод перевода: {transfer_method.replace('requisites', 'По реквизитам').replace('sbp', 'По СБП')}\n"
|
||||
f"Сумма: {amount} единиц\n"
|
||||
f"Пользователь: {user_id}\n\n"
|
||||
f"Подтвердите или отклоните пополнение."
|
||||
)
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(text='Подтвердить', callback_data=f'admin_confirm_replenish_{user_id}_{amount}_{transfer_method}')],
|
||||
[InlineKeyboardButton(text='Отклонить', callback_data=f'admin_decline_replenish_{user_id}')]
|
||||
])
|
||||
|
||||
# Отправляем сообщение администратору
|
||||
await callback_query.message.answer("Запрос на пополнение отправлен администратору.")
|
||||
await bot.send_message(ADMIN_ID, admin_message, reply_markup=keyboard)
|
||||
|
||||
await state.set_state(ReplenishBalanceState.waiting_for_admin_confirmation)
|
||||
await callback_query.answer()
|
||||
|
||||
@router.callback_query(lambda c: c.data.startswith('admin_'))
|
||||
async def process_admin_confirmation(callback_query: types.CallbackQuery, state: FSMContext):
|
||||
if callback_query.from_user.id != ADMIN_ID:
|
||||
await callback_query.answer("Вы не являетесь администратором.")
|
||||
return
|
||||
|
||||
data = callback_query.data.split('_', 4)
|
||||
|
||||
if len(data) < 4:
|
||||
await callback_query.answer("Неверные данные для обработки запроса.")
|
||||
return
|
||||
|
||||
action = data[1] # 'confirm' или 'decline'
|
||||
user_id_str = data[3]
|
||||
|
||||
try:
|
||||
user_id = int(user_id_str) # Преобразование user_id в целое число
|
||||
|
||||
if action == 'confirm':
|
||||
|
||||
amount_str = data[4].split('_')[0]
|
||||
|
||||
# Убедимся, что amount_str действительно является числом
|
||||
if amount_str.isdigit():
|
||||
amount = int(amount_str) # Преобразование amount в целое число
|
||||
else:
|
||||
await callback_query.answer("Неверная сумма для пополнения. Проверьте формат данных.")
|
||||
print(f"Ошибка преобразования суммы: amount_str='{amount_str}'") # Отладочное сообщение в консоль
|
||||
return
|
||||
|
||||
async with aiosqlite.connect(DATABASE_PATH) as db:
|
||||
# Обновляем баланс пользователя
|
||||
await update_balance(user_id, amount)
|
||||
await db.commit()
|
||||
|
||||
balance = await get_balance(user_id)
|
||||
await callback_query.message.answer(f"Баланс пользователя успешно пополнен на {amount} единиц.\nТекущий баланс: {balance}")
|
||||
|
||||
# Сообщаем пользователю о пополнении
|
||||
await bot.send_message(user_id, f"Ваш баланс был успешно пополнен на {amount} RUB.")
|
||||
|
||||
elif action == 'decline':
|
||||
await callback_query.message.answer("Пополнение баланса отклонено.")
|
||||
|
||||
# Сообщаем пользователю об отклонении
|
||||
await bot.send_message(user_id, "Ваш запрос на пополнение баланса был отклонен.")
|
||||
|
||||
except Exception as e:
|
||||
# Отладочное сообщение
|
||||
await callback_query.message.answer(f"Ошибка при пополнении баланса: {e}")
|
||||
print(f"Ошибка при пополнении баланса: {e}") # Отладочное сообщение в консоль
|
||||
|
||||
# Очистка состояния
|
||||
await state.clear()
|
||||
await callback_query.answer()
|
||||
|
||||
+10
-3
@@ -1,7 +1,6 @@
|
||||
from aiogram import types, Router
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, ReplyKeyboardMarkup, KeyboardButton
|
||||
from config import ADMIN_CHAT_ID
|
||||
|
||||
router = Router()
|
||||
|
||||
@@ -13,6 +12,8 @@ async def start_command(message: types.Message):
|
||||
button_view_stats = InlineKeyboardButton(text='Посмотреть статистику', callback_data='view_stats')
|
||||
button_view_expiry = InlineKeyboardButton(text='Дата окончания ключа', callback_data='view_expiry')
|
||||
button_view_profile = InlineKeyboardButton(text='Мой профиль', callback_data='view_profile')
|
||||
|
||||
# Основное меню
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[button_create_key],
|
||||
[button_view_stats],
|
||||
@@ -20,7 +21,13 @@ async def start_command(message: types.Message):
|
||||
[button_view_profile]
|
||||
])
|
||||
|
||||
main_menu_keyboard = ReplyKeyboardMarkup(keyboard=[[KeyboardButton(text="В начало")]], resize_keyboard=True)
|
||||
|
||||
# Отправка приветственного сообщения
|
||||
await message.reply(welcome_text, reply_markup=keyboard)
|
||||
|
||||
# Кнопка "В начало" для возвращения
|
||||
main_menu_keyboard = ReplyKeyboardMarkup(
|
||||
keyboard=[[KeyboardButton(text="В начало")]],
|
||||
resize_keyboard=True
|
||||
)
|
||||
|
||||
await message.answer("Чтобы вернуться в начало, нажмите кнопку ниже:", reply_markup=main_menu_keyboard)
|
||||
|
||||
+6
-2
@@ -15,7 +15,6 @@ import re
|
||||
from bot import dp
|
||||
from handlers.start import start_command
|
||||
from bot import bot
|
||||
from handlers.stats import session
|
||||
|
||||
router = Router()
|
||||
|
||||
@@ -44,6 +43,10 @@ async def process_callback_create_key(callback_query: types.CallbackQuery, state
|
||||
async def handle_text(message: types.Message, state: FSMContext):
|
||||
current_state = await state.get_state()
|
||||
|
||||
if message.text == "/start":
|
||||
await start_command(message)
|
||||
return
|
||||
|
||||
if message.text == "В начало":
|
||||
await start_command(message)
|
||||
return
|
||||
@@ -88,7 +91,8 @@ async def handle_text(message: types.Message, state: FSMContext):
|
||||
async def handle_admin_confirmation(callback_query: CallbackQuery, state: FSMContext):
|
||||
if callback_query.message.chat.id != int(ADMIN_CHAT_ID):
|
||||
return
|
||||
|
||||
|
||||
session = login_with_credentials(ADMIN_USERNAME, ADMIN_PASSWORD)
|
||||
data = callback_query.data.split('_', 3)
|
||||
tg_id = int(data[2])
|
||||
key_name = data[3]
|
||||
|
||||
Reference in New Issue
Block a user