работающая оплата с подтверждением после перевода

This commit is contained in:
Vlad
2024-09-17 23:51:03 +03:00
parent 7fa8d6f346
commit cb9b6381ca
9 changed files with 156 additions and 21 deletions
+3 -1
View File
@@ -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()
+9
View File
@@ -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.
View File
+128 -15
View File
@@ -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
View File
@@ -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
View File
@@ -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]