Управление заказами и добавление товаров (Часть 7)

Управление заказами и добавление товаров (Часть 7)

 В этой статье мы улучшим структуру кода бота Telegram-магазина, разделив команды пользователей и администраторов. Теперь код станет чистым, структурированным и проще в управлении.

💡 Что мы сделаем
✅ Вынесем административные команды в admin_handlers.py
✅ Оставим только команды пользователей в handlers.py
✅ Обновим bot.py, чтобы подключить оба файла
✅ Добавим управление товарами и заказами для админов
✅ Список всех команд для администраторов в конце статьи 📜

Код для admin_handlers.py

Давайте создадим новый файл admin_handlers.py и пропишем туда функции для управления админами, заказами и товарами.

🔹 Обычные администраторы смогут:
✅ Добавлять, удалять товары и изменять их цену
✅ Просматривать список заказов и менять их статус

🔹 Супер-администратор может:
✅ Назначать и удалять администраторов
✅ Просматривать список админов

Импорт библиотек и подключение admin_router

Сначала подключаем все нужные модули и создаем роутер для админских команд.

from aiogram import Router
from aiogram.types import Message
from aiogram.filters import Command
from database import (
    add_product, remove_product, edit_price, get_products,
    get_orders, update_order_status, remove_order,
    add_admin, remove_admin, get_admins, is_admin, is_super_admin
)

admin_router = Router()

Управление товарами 🛍

Теперь рассмотрим функции управления товарами.

Добавление товара

@admin_router.message(Command("add_product"))
async def add_product_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        args = message.text.split(maxsplit=2)
        name, price = args[1], int(args[2])
        add_product(name, price)
        await message.answer(f"✅ Товар **{name}** добавлен с ценой **{price}₽**.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/add_product Название Цена`")

✅ Как это работает?
🔹 Проверяем, является ли отправитель администратором.
🔹 Разбираем сообщение (/add_product Название Цена).
🔹 Добавляем товар в базу данных.

Добавляются товары командой /add_product Название Цена. Например, /add_product Клавиатура 1000 — добавит товар с название «Клавиатура» и ценой 1000 рублей.

Удаление товара

@admin_router.message(Command("remove_product"))
async def remove_product_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        product_id = int(message.text.split()[1])
        remove_product(product_id)
        await message.answer(f"✅ Товар с ID `{product_id}` удален.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/remove_product product_id`")

✅ Как это работает?
🔹 Проверяем права админа.
🔹 Читаем product_id из команды.
🔹 Удаляем товар из базы данных.

Например, /remove_product 2, удалит товар с номером 2. Номера товаров можно посмотреть в списке, выполнив команду /products

Изменение цены товара

@admin_router.message(Command("edit_price"))
async def edit_price_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        product_id, new_price = map(int, message.text.split()[1:3])
        edit_price(product_id, new_price)
        await message.answer(f"✅ Цена товара с ID `{product_id}` изменена на **{new_price}₽**.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/edit_price product_id новая_цена`")

✅ Как это работает?
🔹 Проверяем права.
🔹 Читаем product_id и новую цену.
🔹 Обновляем цену товара в базе.

Например, /edit_price 3 10000, изменит цену товара под номером 3 поменяв цену на 10 000₽.

Просмотр списка товаров

@admin_router.message(Command("products"))
async def list_products_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    products = get_products()
    if not products:
        await message.answer("❌ Товаров пока нет.")
    else:
        product_list = "\n".join([f"📦 **{p[0]}** – {p[1]}, **Цена:** {p[2]}₽" for p in products])
        await message.answer(f"🛒 **Список товаров:**\n{product_list}")

✅ Как это работает?
🔹 Проверяем права.
🔹 Запрашиваем список товаров из базы.
🔹 Отправляем список пользователю.

Посмотреть весь список товаров можно выполнив команду /products

Управление заказами 📦

Просмотр всех заказов

@admin_router.message(Command("orders"))
async def list_orders_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    orders = get_orders()
    if not orders:
        await message.answer("❌ Заказов нет.")
    else:
        order_list = "\n".join([f"📦 **Заказ #{o[0]}** – {o[1]}₽, **Статус:** {o[2]}" for o in orders])
        await message.answer(f"📜 **Список заказов:**\n{order_list}")

✅ Запросит все заказы и выведет их в виде списка.

Посмотреть список заказов можно выполнив команду /orders

Обновление статуса заказа

@admin_router.message(Command("update_order"))
async def update_order_status_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        args = message.text.split(maxsplit=2)
        order_id, new_status = int(args[1]), args[2]
        update_order_status(order_id, new_status)
        await message.answer(f"✅ Статус заказа **#{order_id}** изменен на **{new_status}**.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/update_order order_id новый_статус`")

✅ Позволяет администратору изменить статус заказа.

Изменение выполняется командой /update_order ID Статус. Например, /update_order 2 Ожидает оплату, изменить статус второго заказа на «Ожидает оплату»

Удаление заказа

@admin_router.message(Command("remove_order"))
async def remove_order_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        order_id = int(message.text.split()[1])
        remove_order(order_id)
        await message.answer(f"✅ Заказ **#{order_id}** удален.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/remove_order order_id`")

✅ Позволяет администратору удалить заказ.

Удаляется заказ командой /remove_order ID. Например, /remove_order 3, удалит заказ под номером 3.

Управление администраторами 🛠

🔹 Добавление администратора (только супер-админ)

@admin_router.message(Command("add_admin"))
async def add_admin_handler(message: Message):
    if not is_super_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        user_id = int(message.text.split()[1])
        add_admin(user_id)
        await message.answer(f"✅ Пользователь {user_id} добавлен в администраторы.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/add_admin user_id`")

✅ Супер админ может добавлять нового администратора.

  • /add_admin user_id — Добавить администратора
  • /remove_admin user_id — Удалить администратора
  • /admins — Посмотреть администраторов

Полный код admin_handlers.py:

from aiogram import Router
from aiogram.types import Message
from aiogram.filters import Command
from database import (
    add_product, remove_product, edit_price, get_products,
    get_orders, update_order_status, remove_order,
    add_admin, remove_admin, get_admins, is_admin, is_super_admin
)


admin_router = Router()


### 🔹 ДОБАВЛЕНИЕ ТОВАРА (Только для админов)
@admin_router.message(Command("add_product"))
async def add_product_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        args = message.text.split(maxsplit=2)
        name, price = args[1], int(args[2])
        add_product(name, price)
        await message.answer(f"✅ Товар **{name}** добавлен с ценой **{price}₽**.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/add_product Название Цена`")


### 🔹 УДАЛЕНИЕ ТОВАРА
@admin_router.message(Command("remove_product"))
async def remove_product_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        product_id = int(message.text.split()[1])
        remove_product(product_id)
        await message.answer(f"✅ Товар с ID `{product_id}` удален.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/remove_product product_id`")


### 🔹 ИЗМЕНЕНИЕ ЦЕНЫ ТОВАРА
@admin_router.message(Command("edit_price"))
async def edit_price_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        product_id, new_price = map(int, message.text.split()[1:3])
        edit_price(product_id, new_price)
        await message.answer(f"✅ Цена товара с ID `{product_id}` изменена на **{new_price}₽**.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/edit_price product_id новая_цена`")


### 🔹 ПРОСМОТР СПИСКА ЗАКАЗОВ
@admin_router.message(Command("orders"))
async def list_orders_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    orders = get_orders()
    if not orders:
        await message.answer("❌ Заказов нет.")
    else:
        order_list = "\n".join([f"📦 **Заказ #{o[0]}** – {o[1]}₽, **Статус:** {o[2]}" for o in orders])
        await message.answer(f"📜 **Список заказов:**\n{order_list}")


### 🔹 ОБНОВЛЕНИЕ СТАТУСА ЗАКАЗА
@admin_router.message(Command("update_order"))
async def update_order_status_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        args = message.text.split(maxsplit=2)
        order_id, new_status = int(args[1]), args[2]
        update_order_status(order_id, new_status)
        await message.answer(f"✅ Статус заказа **#{order_id}** изменен на **{new_status}**.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/update_order order_id новый_статус`")


### 🔹 УДАЛЕНИЕ ЗАКАЗА
@admin_router.message(Command("remove_order"))
async def remove_order_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        order_id = int(message.text.split()[1])
        remove_order(order_id)
        await message.answer(f"✅ Заказ **#{order_id}** удален.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/remove_order order_id`")


### 🔹 ДОБАВЛЕНИЕ АДМИНИСТРАТОРА (ТОЛЬКО ДЛЯ СУПЕР-АДМИНА)
@admin_router.message(Command("add_admin"))
async def add_admin_handler(message: Message):
    if not is_super_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        user_id = int(message.text.split()[1])
        add_admin(user_id)
        await message.answer(f"✅ Пользователь {user_id} добавлен в администраторы.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/add_admin user_id`")


### 🔹 УДАЛЕНИЕ АДМИНИСТРАТОРА
@admin_router.message(Command("remove_admin"))
async def remove_admin_handler(message: Message):
    if not is_super_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    try:
        user_id = int(message.text.split()[1])
        if is_super_admin(user_id):
            await message.answer("⚠️ Нельзя удалить супер-администратора!")
        else:
            remove_admin(user_id)
            await message.answer(f"✅ Пользователь {user_id} удален из администраторов.")
    except:
        await message.answer("⚠️ Используйте команду так:\n`/remove_admin user_id`")


### 🔹 СПИСОК АДМИНИСТРАТОРОВ
@admin_router.message(Command("admins"))
async def admins_handler(message: Message):
    if not is_super_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    admins = get_admins()
    if not admins:
        await message.answer("❌ Администраторов нет.")
        return

    text = "👤 **Список администраторов:**\n"
    for user_id, is_super in admins:
        text += f"• `{user_id}` {'(Супер-админ)' if is_super else ''}\n"

    await message.answer(text)


### 🔹 ПРОСМОТР СПИСКА ТОВАРОВ
@admin_router.message(Command("products"))
async def list_products_handler(message: Message):
    if not is_admin(message.from_user.id):
        await message.answer("❌ У вас нет прав для этой команды.")
        return

    products = get_products()
    if not products:
        await message.answer("❌ Товаров пока нет.")
    else:
        product_list = "\n".join([f"📦 **{p[0]}** – {p[1]}, **Цена:** {p[2]}₽" for p in products])
        await message.answer(f"🛒 **Список товаров:**\n{product_list}")

Список доступных команд

Теперь администраторы могут использовать:

🔹 Работа с товарами

  • /add_product Название Цена – добавить товар
  • /remove_product product_id – удалить товар
  • /edit_price product_id новая_цена – изменить цену
  • /products – посмотреть список товаров

🔹 Управление заказами

  • /orders – список заказов
  • /update_order order_id новый_статус – изменить статус заказа
  • /remove_order order_id – удалить заказ

🔹 Администрирование

  • /add_admin user_id – добавить администратора
  • /remove_admin user_id – удалить администратора
  • /admins – список администраторов

Код handlers.py

Теперь можно из handlers.py удалить часть кода который мы добавляли в прошлой статье. Вот так теперь выглядит полный код:

from aiogram import Router, F
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardMarkup, KeyboardButton
from aiogram.filters import Command
from database import get_products, add_to_cart, get_cart, create_order, remove_from_cart
from keyboards import main_menu

router = Router()


### 🔹 ОБРАБОТКА КОМАНДЫ /START
@router.message(Command("start"))
async def start_command(message: Message):
    await message.answer("Добро пожаловать в магазин! Выберите действие: 👇", reply_markup=main_menu)


### 🔹 ОБРАБОТКА КОМАНДЫ "КАТАЛОГ"
@router.message(F.text == "🛍 Каталог")
async def catalog_command(message: Message):
    await message.answer("Вот наш каталог. Выберите товар и укажите его количество:")

    products = get_products()
    for product in products:
        product_id, name, price = product
        keyboard = InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="➕ Добавить", callback_data=f"add_{product_id}")],
            [InlineKeyboardButton(text="➖ Убрать", callback_data=f"remove_{product_id}")]
        ])
        await message.answer(f"{name} - {price}₽", reply_markup=keyboard)


### 🔹 ОБРАБОТКА КНОПОК "ДОБАВИТЬ" И "УДАЛИТЬ"
@router.callback_query(F.data.startswith("add_") | F.data.startswith("remove_"))
async def update_cart_handler(callback: CallbackQuery):
    action, product_id = callback.data.split("_")
    product_id = int(product_id)

    if action == "add":
        add_to_cart(callback.from_user.id, product_id)
        await callback.answer("✅ Товар добавлен!")
    elif action == "remove":
        remove_from_cart(callback.from_user.id, product_id)
        await callback.answer("❌ Товар убран!")


### 🔹 ОБРАБОТКА КОМАНДЫ "КОРЗИНА" + КНОПКА "ОБНОВИТЬ"
@router.message(F.text == "🛒 Корзина")
@router.callback_query(F.data == "refresh_cart")
async def cart_command(event):
    user_id = event.from_user.id if isinstance(event, CallbackQuery) else event.from_user.id

    cart_items = get_cart(user_id)

    if not cart_items:
        await event.message.answer("Ваша корзина пуста.")
    else:
        cart_text = "🛒 Ваша корзина:\n"
        total_price = 0
        keyboard_buttons = []

        for name, quantity, price, product_id in cart_items:
            total_price += quantity * price
            cart_text += f"{name} — {quantity} шт. × {price}₽ = {quantity * price}₽\n"

            keyboard_buttons.append([
                InlineKeyboardButton(text="➕", callback_data=f"add_{product_id}"),
                InlineKeyboardButton(text="➖", callback_data=f"remove_{product_id}")
            ])

        cart_text += f"\n💰 Итоговая сумма: {total_price}₽"

        keyboard_buttons.append([
            InlineKeyboardButton(text="🔄 Обновить корзину", callback_data="refresh_cart")
        ])
        keyboard_buttons.append([
            InlineKeyboardButton(text="✅ Оформить заказ", callback_data="checkout")
        ])

        keyboard = InlineKeyboardMarkup(inline_keyboard=keyboard_buttons)

        if isinstance(event, CallbackQuery):
            await event.message.edit_text(cart_text, reply_markup=keyboard)
            await event.answer()
        else:
            await event.answer(cart_text, reply_markup=keyboard)


### 🔹 ОБРАБОТКА "ОФОРМИТЬ ЗАКАЗ"
@router.callback_query(F.data == "checkout")
async def request_contact(callback: CallbackQuery):
    contact_keyboard = ReplyKeyboardMarkup(
        keyboard=[[KeyboardButton(text="📱 Отправить номер", request_contact=True)]],
        resize_keyboard=True,
        one_time_keyboard=True
    )
    await callback.message.answer("📱 Отправьте свой номер телефона для оформления заказа:", reply_markup=contact_keyboard)
    await callback.answer()


### 🔹 ПОЛУЧЕНИЕ НОМЕРА ТЕЛЕФОНА
@router.message(F.contact | F.text.regexp(r'^\+?\d{10,15}$'))
async def receive_contact(message: Message):
    phone_number = message.contact.phone_number if message.contact else message.text
    order_id = create_order(message.from_user.id)

    if order_id:
        await message.answer(f"✅ Заказ #{order_id} оформлен!\n📞 Мы свяжемся с вами по номеру: {phone_number}.")
    else:
        await message.answer("❌ Ваша корзина пуста, добавьте товары перед заказом.")

Код bot.py

В bot.py нужно изменить код чтобы он мог обрабатывать пользовательские и админские функции. Вот полный код:

import asyncio
import os
from aiogram import Bot, Dispatcher
from dotenv import load_dotenv
from handlers import router
from admin_handlers import admin_router  # Подключаем новый файл
import database

# Загружаем токен
load_dotenv()
BOT_TOKEN = os.getenv("BOT_TOKEN")

if not BOT_TOKEN:
    raise ValueError("Ошибка: BOT_TOKEN не найден. Проверьте файл .env!")

bot = Bot(token=BOT_TOKEN)
dp = Dispatcher()

# Подключаем обработчики
dp.include_router(router)  # Обычные команды
dp.include_router(admin_router)  # Админские команды

async def main():
    print("Бот запущен...")
    database
    await bot.delete_webhook(drop_pending_updates=True)
    await dp.start_polling(bot)

if __name__ == "__main__":
    asyncio.run(main())

На этом наш телеграм магазин готов. В следующей статье мы подведем итоги и напишем весь полный код нашего магазина.

Комментарии

Пока нет комментариев. Будьте первым!

Оставить комментарий

Чтобы оставить комментарий, пожалуйста, войдите или зарегистрируйтесь.