This commit is contained in:
2025-06-08 20:55:08 +09:00
parent f7e0d17829
commit 7a75f79413
139 changed files with 10619 additions and 2340 deletions

View File

@@ -0,0 +1,4 @@
from .admin import dp
from .user import dp
__all__ = ['dp']

View File

@@ -0,0 +1,5 @@
from .add import dp
from .questions import dp
from .orders import dp
__all__ = ['dp']

View File

@@ -0,0 +1,285 @@
from aiogram.dispatcher import FSMContext
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton, ContentType, ReplyKeyboardMarkup, ReplyKeyboardRemove
from aiogram.utils.callback_data import CallbackData
from keyboards.default.markups import *
from states import ProductState, CategoryState
from aiogram.types.chat import ChatActions
from doners.old_2.handlers import settings
from loader import dp, db, bot
from filters import IsAdmin
from hashlib import md5
category_cb = CallbackData('category', 'id', 'action')
product_cb = CallbackData('product', 'id', 'action')
add_product = ' Добавить товар'
delete_category = '🗑️ Удалить категорию'
@dp.message_handler(IsAdmin(), text=settings)
async def process_settings(message: Message):
markup = InlineKeyboardMarkup()
for idx, title in db.fetchall('SELECT * FROM categories'):
markup.add(InlineKeyboardButton(
title, callback_data=category_cb.new(id=idx, action='view')))
markup.add(InlineKeyboardButton(
'+ Добавить категорию', callback_data='add_category'))
await message.answer('Настройка категорий:', reply_markup=markup)
@dp.callback_query_handler(IsAdmin(), category_cb.filter(action='view'))
async def category_callback_handler(query: CallbackQuery, callback_data: dict, state: FSMContext):
category_idx = callback_data['id']
products = db.fetchall('''SELECT * FROM products product
WHERE product.tag = (SELECT title FROM categories WHERE idx=?)''',
(category_idx,))
await query.message.delete()
await query.answer('Все добавленные товары в эту категорию.')
await state.update_data(category_index=category_idx)
await show_products(query.message, products, category_idx)
# category
@dp.callback_query_handler(IsAdmin(), text='add_category')
async def add_category_callback_handler(query: CallbackQuery):
await query.message.delete()
await query.message.answer('Название категории?')
await CategoryState.title.set()
@dp.message_handler(IsAdmin(), state=CategoryState.title)
async def set_category_title_handler(message: Message, state: FSMContext):
category = message.text
idx = md5(category.encode('utf-8')).hexdigest()
db.query('INSERT INTO categories VALUES (?, ?)', (idx, category))
await state.finish()
await process_settings(message)
@dp.message_handler(IsAdmin(), text=delete_category)
async def delete_category_handler(message: Message, state: FSMContext):
async with state.proxy() as data:
if 'category_index' in data.keys():
idx = data['category_index']
db.query(
'DELETE FROM products WHERE tag IN (SELECT title FROM categories WHERE idx=?)', (idx,))
db.query('DELETE FROM categories WHERE idx=?', (idx,))
await message.answer('Готово!', reply_markup=ReplyKeyboardRemove())
await process_settings(message)
# add product
@dp.message_handler(IsAdmin(), text=add_product)
async def process_add_product(message: Message):
await ProductState.title.set()
markup = ReplyKeyboardMarkup(resize_keyboard=True)
markup.add(cancel_message)
await message.answer('Название?', reply_markup=markup)
@dp.message_handler(IsAdmin(), text=cancel_message, state=ProductState.title)
async def process_cancel(message: Message, state: FSMContext):
await message.answer('Ок, отменено!', reply_markup=ReplyKeyboardRemove())
await state.finish()
await process_settings(message)
@dp.message_handler(IsAdmin(), text=back_message, state=ProductState.title)
async def process_title_back(message: Message, state: FSMContext):
await process_add_product(message)
@dp.message_handler(IsAdmin(), state=ProductState.title)
async def process_title(message: Message, state: FSMContext):
async with state.proxy() as data:
data['title'] = message.text
await ProductState.next()
await message.answer('Описание?', reply_markup=back_markup())
@dp.message_handler(IsAdmin(), text=back_message, state=ProductState.body)
async def process_body_back(message: Message, state: FSMContext):
await ProductState.title.set()
async with state.proxy() as data:
await message.answer(f"Изменить название с <b>{data['title']}</b>?", reply_markup=back_markup())
@dp.message_handler(IsAdmin(), state=ProductState.body)
async def process_body(message: Message, state: FSMContext):
async with state.proxy() as data:
data['body'] = message.text
await ProductState.next()
await message.answer('Фото?', reply_markup=back_markup())
@dp.message_handler(IsAdmin(), content_types=ContentType.PHOTO, state=ProductState.image)
async def process_image_photo(message: Message, state: FSMContext):
fileID = message.photo[-1].file_id
file_info = await bot.get_file(fileID)
downloaded_file = (await bot.download_file(file_info.file_path)).read()
async with state.proxy() as data:
data['image'] = downloaded_file
await ProductState.next()
await message.answer('Цена?', reply_markup=back_markup())
@dp.message_handler(IsAdmin(), content_types=ContentType.TEXT, state=ProductState.image)
async def process_image_url(message: Message, state: FSMContext):
if message.text == back_message:
await ProductState.body.set()
async with state.proxy() as data:
await message.answer(f"Изменить описание с <b>{data['body']}</b>?", reply_markup=back_markup())
else:
await message.answer('Вам нужно прислать фото товара.')
@dp.message_handler(IsAdmin(), lambda message: not message.text.isdigit(), state=ProductState.price)
async def process_price_invalid(message: Message, state: FSMContext):
if message.text == back_message:
await ProductState.image.set()
async with state.proxy() as data:
await message.answer("Другое изображение?", reply_markup=back_markup())
else:
await message.answer('Укажите цену в виде числа!')
@dp.message_handler(IsAdmin(), lambda message: message.text.isdigit(), state=ProductState.price)
async def process_price(message: Message, state: FSMContext):
async with state.proxy() as data:
data['price'] = message.text
title = data['title']
body = data['body']
price = data['price']
await ProductState.next()
text = f'<b>{title}</b>\n\n{body}\n\nЦена: {price} рублей.'
markup = check_markup()
await message.answer_photo(photo=data['image'],
caption=text,
reply_markup=markup)
@dp.message_handler(IsAdmin(), lambda message: message.text not in [back_message, all_right_message], state=ProductState.confirm)
async def process_confirm_invalid(message: Message, state: FSMContext):
await message.answer('Такого варианта не было.')
@dp.message_handler(IsAdmin(), text=back_message, state=ProductState.confirm)
async def process_confirm_back(message: Message, state: FSMContext):
await ProductState.price.set()
async with state.proxy() as data:
await message.answer(f"Изменить цену с <b>{data['price']}</b>?", reply_markup=back_markup())
@dp.message_handler(IsAdmin(), text=all_right_message, state=ProductState.confirm)
async def process_confirm(message: Message, state: FSMContext):
async with state.proxy() as data:
title = data['title']
body = data['body']
image = data['image']
price = data['price']
tag = db.fetchone(
'SELECT title FROM categories WHERE idx=?', (data['category_index'],))[0]
idx = md5(' '.join([title, body, price, tag]
).encode('utf-8')).hexdigest()
db.query('INSERT INTO products VALUES (?, ?, ?, ?, ?, ?)',
(idx, title, body, image, int(price), tag))
await state.finish()
await message.answer('Готово!', reply_markup=ReplyKeyboardRemove())
await process_settings(message)
# delete product
@dp.callback_query_handler(IsAdmin(), product_cb.filter(action='delete'))
async def delete_product_callback_handler(query: CallbackQuery, callback_data: dict):
product_idx = callback_data['id']
db.query('DELETE FROM products WHERE idx=?', (product_idx,))
await query.answer('Удалено!')
await query.message.delete()
async def show_products(m, products, category_idx):
await bot.send_chat_action(m.chat.id, ChatActions.TYPING)
for idx, title, body, image, price, tag in products:
text = f'<b>{title}</b>\n\n{body}\n\nЦена: {price} рублей.'
markup = InlineKeyboardMarkup()
markup.add(InlineKeyboardButton(
'🗑️ Удалить', callback_data=product_cb.new(id=idx, action='delete')))
await m.answer_photo(photo=image,
caption=text,
reply_markup=markup)
markup = ReplyKeyboardMarkup()
markup.add(add_product)
markup.add(delete_category)
await m.answer('Хотите что-нибудь добавить или удалить?', reply_markup=markup)

View File

@@ -0,0 +1,22 @@
from aiogram.types import Message
from loader import dp, db
from doners.old_2.handlers import orders
from filters import IsAdmin
@dp.message_handler(IsAdmin(), text=orders)
async def process_orders(message: Message):
orders = db.fetchall('SELECT * FROM orders')
if len(orders) == 0: await message.answer('У вас нет заказов.')
else: await order_answer(message, orders)
async def order_answer(message, orders):
res = ''
for order in orders:
res += f'Заказ <b>№{order[3]}</b>\n\n'
await message.answer(res)

View File

@@ -0,0 +1,78 @@
from doners.old_2.handlers import questions
from aiogram.dispatcher import FSMContext
from aiogram.utils.callback_data import CallbackData
from keyboards.default.markups import all_right_message, cancel_message, submit_markup
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove
from aiogram.types.chat import ChatActions
from states import AnswerState
from loader import dp, db, bot
from filters import IsAdmin
question_cb = CallbackData('question', 'cid', 'action')
@dp.message_handler(IsAdmin(), text=questions)
async def process_questions(message: Message):
await bot.send_chat_action(message.chat.id, ChatActions.TYPING)
questions = db.fetchall('SELECT * FROM questions')
if len(questions) == 0:
await message.answer('Нет вопросов.')
else:
for cid, question in questions:
markup = InlineKeyboardMarkup()
markup.add(InlineKeyboardButton(
'Ответить', callback_data=question_cb.new(cid=cid, action='answer')))
await message.answer(question, reply_markup=markup)
@dp.callback_query_handler(IsAdmin(), question_cb.filter(action='answer'))
async def process_answer(query: CallbackQuery, callback_data: dict, state: FSMContext):
async with state.proxy() as data:
data['cid'] = callback_data['cid']
await query.message.answer('Напиши ответ.', reply_markup=ReplyKeyboardRemove())
await AnswerState.answer.set()
@dp.message_handler(IsAdmin(), state=AnswerState.answer)
async def process_submit(message: Message, state: FSMContext):
async with state.proxy() as data:
data['answer'] = message.text
await AnswerState.next()
await message.answer('Убедитесь, что не ошиблись в ответе.', reply_markup=submit_markup())
@dp.message_handler(IsAdmin(), text=cancel_message, state=AnswerState.submit)
async def process_send_answer(message: Message, state: FSMContext):
await message.answer('Отменено!', reply_markup=ReplyKeyboardRemove())
await state.finish()
@dp.message_handler(IsAdmin(), text=all_right_message, state=AnswerState.submit)
async def process_send_answer(message: Message, state: FSMContext):
async with state.proxy() as data:
answer = data['answer']
cid = data['cid']
question = db.fetchone(
'SELECT question FROM questions WHERE cid=?', (cid,))[0]
db.query('DELETE FROM questions WHERE cid=?', (cid,))
text = f'Вопрос: <b>{question}</b>\n\nОтвет: <b>{answer}</b>'
await message.answer('Отправлено!', reply_markup=ReplyKeyboardRemove())
await bot.send_message(cid, text)
await state.finish()

View File

@@ -0,0 +1,8 @@
from .menu import dp
from .cart import dp
from .wallet import dp
from .catalog import dp
from .delivery_status import dp
from .sos import dp
__all__ = ['dp']

View File

@@ -0,0 +1,247 @@
import logging
from aiogram.dispatcher import FSMContext
from aiogram.types import Message, CallbackQuery, ReplyKeyboardMarkup, ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton
from keyboards.inline.products_from_cart import product_markup, product_cb
from aiogram.utils.callback_data import CallbackData
from keyboards.default.markups import *
from aiogram.types.chat import ChatActions
from states import CheckoutState
from loader import dp, db, bot
from filters import IsUser
from .menu import cart
@dp.message_handler(IsUser(), text=cart)
async def process_cart(message: Message, state: FSMContext):
cart_data = db.fetchall(
'SELECT * FROM cart WHERE cid=?', (message.chat.id,))
if len(cart_data) == 0:
await message.answer('Ваша корзина пуста.')
else:
await bot.send_chat_action(message.chat.id, ChatActions.TYPING)
async with state.proxy() as data:
data['products'] = {}
order_cost = 0
for _, idx, count_in_cart in cart_data:
product = db.fetchone('SELECT * FROM products WHERE idx=?', (idx,))
if product == None:
db.query('DELETE FROM cart WHERE idx=?', (idx,))
else:
_, title, body, image, price, _ = product
order_cost += price
async with state.proxy() as data:
data['products'][idx] = [title, price, count_in_cart]
markup = product_markup(idx, count_in_cart)
text = f'<b>{title}</b>\n\n{body}\n\nЦена: {price}₽.'
await message.answer_photo(photo=image,
caption=text,
reply_markup=markup)
if order_cost != 0:
markup = ReplyKeyboardMarkup(resize_keyboard=True, selective=True)
markup.add('📦 Оформить заказ')
await message.answer('Перейти к оформлению?',
reply_markup=markup)
@dp.callback_query_handler(IsUser(), product_cb.filter(action='count'))
@dp.callback_query_handler(IsUser(), product_cb.filter(action='increase'))
@dp.callback_query_handler(IsUser(), product_cb.filter(action='decrease'))
async def product_callback_handler(query: CallbackQuery, callback_data: dict, state: FSMContext):
idx = callback_data['id']
action = callback_data['action']
if 'count' == action:
async with state.proxy() as data:
if 'products' not in data.keys():
await process_cart(query.message, state)
else:
await query.answer('Количество - ' + data['products'][idx][2])
else:
async with state.proxy() as data:
if 'products' not in data.keys():
await process_cart(query.message, state)
else:
data['products'][idx][2] += 1 if 'increase' == action else -1
count_in_cart = data['products'][idx][2]
if count_in_cart == 0:
db.query('''DELETE FROM cart
WHERE cid = ? AND idx = ?''', (query.message.chat.id, idx))
await query.message.delete()
else:
db.query('''UPDATE cart
SET quantity = ?
WHERE cid = ? AND idx = ?''', (count_in_cart, query.message.chat.id, idx))
await query.message.edit_reply_markup(product_markup(idx, count_in_cart))
@dp.message_handler(IsUser(), text='📦 Оформить заказ')
async def process_checkout(message: Message, state: FSMContext):
await CheckoutState.check_cart.set()
await checkout(message, state)
async def checkout(message, state):
answer = ''
total_price = 0
async with state.proxy() as data:
for title, price, count_in_cart in data['products'].values():
tp = count_in_cart * price
answer += f'<b>{title}</b> * {count_in_cart}шт. = {tp}\n'
total_price += tp
await message.answer(f'{answer}\nОбщая сумма заказа: {total_price}₽.',
reply_markup=check_markup())
@dp.message_handler(IsUser(), lambda message: message.text not in [all_right_message, back_message], state=CheckoutState.check_cart)
async def process_check_cart_invalid(message: Message):
await message.reply('Такого варианта не было.')
@dp.message_handler(IsUser(), text=back_message, state=CheckoutState.check_cart)
async def process_check_cart_back(message: Message, state: FSMContext):
await state.finish()
await process_cart(message, state)
@dp.message_handler(IsUser(), text=all_right_message, state=CheckoutState.check_cart)
async def process_check_cart_all_right(message: Message, state: FSMContext):
await CheckoutState.next()
await message.answer('Укажите свое имя.',
reply_markup=back_markup())
@dp.message_handler(IsUser(), text=back_message, state=CheckoutState.name)
async def process_name_back(message: Message, state: FSMContext):
await CheckoutState.check_cart.set()
await checkout(message, state)
@dp.message_handler(IsUser(), state=CheckoutState.name)
async def process_name(message: Message, state: FSMContext):
async with state.proxy() as data:
data['name'] = message.text
if 'address' in data.keys():
await confirm(message)
await CheckoutState.confirm.set()
else:
await CheckoutState.next()
await message.answer('Укажите свой адрес места жительства.',
reply_markup=back_markup())
@dp.message_handler(IsUser(), text=back_message, state=CheckoutState.address)
async def process_address_back(message: Message, state: FSMContext):
async with state.proxy() as data:
await message.answer('Изменить имя с <b>' + data['name'] + '</b>?',
reply_markup=back_markup())
await CheckoutState.name.set()
@dp.message_handler(IsUser(), state=CheckoutState.address)
async def process_address(message: Message, state: FSMContext):
async with state.proxy() as data:
data['address'] = message.text
await confirm(message)
await CheckoutState.next()
async def confirm(message):
await message.answer('Убедитесь, что все правильно оформлено и подтвердите заказ.',
reply_markup=confirm_markup())
@dp.message_handler(IsUser(), lambda message: message.text not in [confirm_message, back_message], state=CheckoutState.confirm)
async def process_confirm_invalid(message: Message):
await message.reply('Такого варианта не было.')
@dp.message_handler(IsUser(), text=back_message, state=CheckoutState.confirm)
async def process_confirm(message: Message, state: FSMContext):
await CheckoutState.address.set()
async with state.proxy() as data:
await message.answer('Изменить адрес с <b>' + data['address'] + '</b>?',
reply_markup=back_markup())
@dp.message_handler(IsUser(), text=confirm_message, state=CheckoutState.confirm)
async def process_confirm(message: Message, state: FSMContext):
enough_money = True # enough money on the balance sheet
markup = ReplyKeyboardRemove()
if enough_money:
logging.info('Deal was made.')
async with state.proxy() as data:
cid = message.chat.id
products = [idx + '=' + str(quantity)
for idx, quantity in db.fetchall('''SELECT idx, quantity FROM cart
WHERE cid=?''', (cid,))] # idx=quantity
db.query('INSERT INTO orders VALUES (?, ?, ?, ?)',
(cid, data['name'], data['address'], ' '.join(products)))
db.query('DELETE FROM cart WHERE cid=?', (cid,))
await message.answer('Ок! Ваш заказ уже в пути 🚀\nИмя: <b>' + data['name'] + '</b>\nАдрес: <b>' + data['address'] + '</b>',
reply_markup=markup)
else:
await message.answer('У вас недостаточно денег на счете. Пополните баланс!',
reply_markup=markup)
await state.finish()

View File

@@ -0,0 +1,58 @@
import logging
from aiogram.types import Message, CallbackQuery
from keyboards.inline.categories import categories_markup, category_cb
from keyboards.inline.products_from_catalog import product_markup, product_cb
from aiogram.utils.callback_data import CallbackData
from aiogram.types.chat import ChatActions
from loader import dp, db, bot
from .menu import catalog
from filters import IsUser
@dp.message_handler(IsUser(), text=catalog)
async def process_catalog(message: Message):
await message.answer('Выберите раздел, чтобы вывести список товаров:',
reply_markup=categories_markup())
@dp.callback_query_handler(IsUser(), category_cb.filter(action='view'))
async def category_callback_handler(query: CallbackQuery, callback_data: dict):
products = db.fetchall('''SELECT * FROM products product
WHERE product.tag = (SELECT title FROM categories WHERE idx=?)
AND product.idx NOT IN (SELECT idx FROM cart WHERE cid = ?)''',
(callback_data['id'], query.message.chat.id))
await query.answer('Все доступные товары.')
await show_products(query.message, products)
@dp.callback_query_handler(IsUser(), product_cb.filter(action='add'))
async def add_product_callback_handler(query: CallbackQuery, callback_data: dict):
db.query('INSERT INTO cart VALUES (?, ?, 1)',
(query.message.chat.id, callback_data['id']))
await query.answer('Товар добавлен в корзину!')
await query.message.delete()
async def show_products(m, products):
if len(products) == 0:
await m.answer('Здесь ничего нет 😢')
else:
await bot.send_chat_action(m.chat.id, ChatActions.TYPING)
for idx, title, body, image, price, _ in products:
markup = product_markup(idx, price)
text = f'<b>{title}</b>\n\n{body}'
await m.answer_photo(photo=image,
caption=text,
reply_markup=markup)

View File

@@ -0,0 +1,31 @@
from aiogram.types import Message
from loader import dp, db
from .menu import delivery_status
from filters import IsUser
@dp.message_handler(IsUser(), text=delivery_status)
async def process_delivery_status(message: Message):
orders = db.fetchall('SELECT * FROM orders WHERE cid=?', (message.chat.id,))
if len(orders) == 0: await message.answer('У вас нет активных заказов.')
else: await delivery_status_answer(message, orders)
async def delivery_status_answer(message, orders):
res = ''
for order in orders:
res += f'Заказ <b>№{order[3]}</b>'
answer = [
' лежит на складе.',
' уже в пути!',
' прибыл и ждет вас на почте!'
]
res += answer[0]
res += '\n\n'
await message.answer(res)

View File

@@ -0,0 +1,30 @@
from aiogram.types import Message, CallbackQuery, ReplyKeyboardMarkup
from loader import dp
from filters import IsAdmin, IsUser
catalog = '🛍️ Каталог'
balance = '💰 Баланс'
cart = '🛒 Корзина'
delivery_status = '🚚 Статус заказа'
settings = '⚙️ Настройка каталога'
orders = '🚚 Заказы'
questions = '❓ Вопросы'
@dp.message_handler(IsAdmin(), commands='menu')
async def admin_menu(message: Message):
markup = ReplyKeyboardMarkup(selective=True)
markup.add(settings)
markup.add(questions, orders)
await message.answer('Меню', reply_markup=markup)
@dp.message_handler(IsUser(), commands='menu')
async def user_menu(message: Message):
markup = ReplyKeyboardMarkup(selective=True)
markup.add(catalog)
markup.add(balance, cart)
markup.add(delivery_status)
await message.answer('Меню', reply_markup=markup)

View File

@@ -0,0 +1,54 @@
from aiogram.dispatcher import FSMContext
from aiogram.types import ReplyKeyboardMarkup, ReplyKeyboardRemove
from keyboards.default.markups import all_right_message, cancel_message, submit_markup
from aiogram.types import Message
from states import SosState
from filters import IsUser
from loader import dp, db
@dp.message_handler(commands='sos')
async def cmd_sos(message: Message):
await SosState.question.set()
await message.answer('В чем суть проблемы? Опишите как можно детальнее и администратор обязательно вам ответит.', reply_markup=ReplyKeyboardRemove())
@dp.message_handler(state=SosState.question)
async def process_question(message: Message, state: FSMContext):
async with state.proxy() as data:
data['question'] = message.text
await message.answer('Убедитесь, что все верно.', reply_markup=submit_markup())
await SosState.next()
@dp.message_handler(lambda message: message.text not in [cancel_message, all_right_message], state=SosState.submit)
async def process_price_invalid(message: Message):
await message.answer('Такого варианта не было.')
@dp.message_handler(text=cancel_message, state=SosState.submit)
async def process_cancel(message: Message, state: FSMContext):
await message.answer('Отменено!', reply_markup=ReplyKeyboardRemove())
await state.finish()
@dp.message_handler(text=all_right_message, state=SosState.submit)
async def process_submit(message: Message, state: FSMContext):
cid = message.chat.id
if db.fetchone('SELECT * FROM questions WHERE cid=?', (cid,)) == None:
async with state.proxy() as data:
db.query('INSERT INTO questions VALUES (?, ?)',
(cid, data['question']))
await message.answer('Отправлено!', reply_markup=ReplyKeyboardRemove())
else:
await message.answer('Превышен лимит на количество задаваемых вопросов.', reply_markup=ReplyKeyboardRemove())
await state.finish()

View File

@@ -0,0 +1,18 @@
from loader import dp
from aiogram.dispatcher import FSMContext
from aiogram.types import Message
from filters import IsUser
from .menu import balance
# test card ==> 1111 1111 1111 1026, 12/22, CVC 000
# shopId 506751
# shopArticleId 538350
@dp.message_handler(IsUser(), text=balance)
async def process_balance(message: Message, state: FSMContext):
await message.answer('Ваш кошелек пуст! Чтобы его пополнить нужно...')