Теперь, когда пользователи могут добавлять товары в корзину, нам нужно сделать процесс оформления заказа максимально удобным. В этой статье мы:
✅ Добавим кнопку «Оформить заказ».
✅ Запросим номер телефона перед оформлением.
✅ Добавим возможность увеличивать и уменьшать количество товаров в корзине.
✅ Сделаем кнопку «🔄 Обновить корзину», чтобы сразу видеть изменения.
Обновляем базу данных
Перед добавлением новых функций нам нужно удалить старую базу данных, так как мы изменяем структуру таблиц.
Удаляем старую базу
Запусти команду в терминале или удалите её в ручную:
rm shop.db # Для Linux и Mac
del shop.db # Для Windows
Теперь база данных удалена, и мы можем пересоздать её с нужными таблицами.
Создаём обновленную базу данных (database.py
)
Теперь создадим базу данных с корзиной, заказами и возможностью изменять количество товаров.
import sqlite3
conn = sqlite3.connect("shop.db")
cursor = conn.cursor()
# Таблица товаров
cursor.execute("""
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price INTEGER NOT NULL
)
""")
# Таблица корзины
cursor.execute("""
CREATE TABLE IF NOT EXISTS cart (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
product_id INTEGER NOT NULL,
quantity INTEGER NOT NULL,
FOREIGN KEY (product_id) REFERENCES products (id)
)
""")
# Таблица заказов
cursor.execute("""
CREATE TABLE IF NOT EXISTS orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
total_price INTEGER NOT NULL,
status TEXT NOT NULL DEFAULT 'pending'
)
""")
conn.commit()
conn.close()
✅ Что изменилось?
- Теперь корзина поддерживает изменение количества товаров.
- Полностью удаляем старую таблицу
orders
и создаем новую.
Теперь запусти database.py
, чтобы создать новую базу данных: python database.py
Так как мы удаляли полностью базу, то и тестовые товары у нас удалились.
Чтобы добавить несколько тестовых товары, можно запустить Python-скрипт вручную.
✅ Открой терминал и запусти Python:
Далее в интерактивном режиме выполни команды:
from database import add_product
add_product("📦 Товар A", 100)
add_product("📦 Товар B", 200)
add_product("📦 Товар C", 300)
print("Товары добавлены!")
После этого товары появятся в базе.
Проверка списка товаров
Чтобы убедиться, что товары записаны, в терминале введи:
from database import get_products
print(get_products())
Ты увидишь список товаров в виде:
Функции управления корзиной
Сделаем возможность добавлять товары, изменять их количество и удалять из корзины.
def add_to_cart(user_id, product_id, quantity=1):
"""Добавляет товар в корзину или увеличивает его количество"""
conn = sqlite3.connect("shop.db")
cursor = conn.cursor()
cursor.execute("SELECT quantity FROM cart WHERE user_id=? AND product_id=?", (user_id, product_id))
result = cursor.fetchone()
if result:
new_quantity = result[0] + quantity
cursor.execute("UPDATE cart SET quantity=? WHERE user_id=? AND product_id=?", (new_quantity, user_id, product_id))
else:
cursor.execute("INSERT INTO cart (user_id, product_id, quantity) VALUES (?, ?, ?)", (user_id, product_id, quantity))
conn.commit()
conn.close()
def remove_from_cart(user_id, product_id):
"""Удаляет 1 шт. товара из корзины, если количество > 1, иначе удаляет полностью"""
conn = sqlite3.connect("shop.db")
cursor = conn.cursor()
cursor.execute("SELECT quantity FROM cart WHERE user_id=? AND product_id=?", (user_id, product_id))
result = cursor.fetchone()
if result:
if result[0] > 1:
new_quantity = result[0] - 1
cursor.execute("UPDATE cart SET quantity=? WHERE user_id=? AND product_id=?", (new_quantity, user_id, product_id))
else:
cursor.execute("DELETE FROM cart WHERE user_id=? AND product_id=?", (user_id, product_id))
conn.commit()
conn.close()
✅ Что изменилось?
- Теперь можно увеличить или уменьшить количество товаров в корзине.
- Если товар удаляется полностью, он исчезает из корзины.
В итоге полный код database.py
должен быть такой:
import sqlite3
# Подключаемся к базе данных (если файла нет, он создастся автоматически)
conn = sqlite3.connect("shop.db")
cursor = conn.cursor()
# Таблица товаров
cursor.execute("""
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price INTEGER NOT NULL
)
""")
# Таблица корзины
cursor.execute("""
CREATE TABLE IF NOT EXISTS cart (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
product_id INTEGER NOT NULL,
quantity INTEGER NOT NULL,
FOREIGN KEY (product_id) REFERENCES products (id)
)
""")
# Таблица заказов
cursor.execute("""
CREATE TABLE IF NOT EXISTS orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
total_price INTEGER NOT NULL,
status TEXT NOT NULL DEFAULT 'pending'
)
""")
conn.commit()
conn.close()
def add_product(name, price):
"""Добавляет товар в базу данных"""
conn = sqlite3.connect("shop.db")
cursor = conn.cursor()
cursor.execute("INSERT INTO products (name, price) VALUES (?, ?)", (name, price))
conn.commit()
conn.close()
def get_products():
"""Получает список всех товаров"""
conn = sqlite3.connect("shop.db")
cursor = conn.cursor()
cursor.execute("SELECT * FROM products")
products = cursor.fetchall()
conn.close()
return products
def add_to_cart(user_id, product_id, quantity=1):
"""Добавляет товар в корзину пользователя с указанием количества"""
conn = sqlite3.connect("shop.db")
cursor = conn.cursor()
cursor.execute("SELECT quantity FROM cart WHERE user_id=? AND product_id=?", (user_id, product_id))
result = cursor.fetchone()
if result:
new_quantity = result[0] + quantity
cursor.execute("UPDATE cart SET quantity=? WHERE user_id=? AND product_id=?", (new_quantity, user_id, product_id))
else:
cursor.execute("INSERT INTO cart (user_id, product_id, quantity) VALUES (?, ?, ?)", (user_id, product_id, quantity))
conn.commit()
conn.close()
def remove_from_cart(user_id, product_id):
"""Удаляет 1 шт. товара из корзины, если количество > 1, иначе удаляет полностью"""
conn = sqlite3.connect("shop.db")
cursor = conn.cursor()
cursor.execute("SELECT quantity FROM cart WHERE user_id=? AND product_id=?", (user_id, product_id))
result = cursor.fetchone()
if result:
if result[0] > 1:
new_quantity = result[0] - 1
cursor.execute("UPDATE cart SET quantity=? WHERE user_id=? AND product_id=?", (new_quantity, user_id, product_id))
else:
cursor.execute("DELETE FROM cart WHERE user_id=? AND product_id=?", (user_id, product_id))
conn.commit()
conn.close()
def get_cart(user_id):
"""Возвращает список товаров в корзине пользователя"""
conn = sqlite3.connect("shop.db")
cursor = conn.cursor()
cursor.execute("""
SELECT products.name, cart.quantity, products.price, products.id
FROM cart
JOIN products ON cart.product_id = products.id
WHERE cart.user_id=?
""", (user_id,))
cart_items = cursor.fetchall()
conn.close()
return cart_items
def create_order(user_id):
"""Создает заказ из корзины пользователя"""
conn = sqlite3.connect("shop.db")
cursor = conn.cursor()
cursor.execute("""
SELECT products.id, products.price, cart.quantity
FROM cart
JOIN products ON cart.product_id = products.id
WHERE cart.user_id=?
""", (user_id,))
cart_items = cursor.fetchall()
if not cart_items:
conn.close()
return None
total_price = sum(item[1] * item[2] for item in cart_items)
cursor.execute("INSERT INTO orders (user_id, total_price) VALUES (?, ?)", (user_id, total_price))
order_id = cursor.lastrowid
cursor.execute("DELETE FROM cart WHERE user_id=?", (user_id,))
conn.commit()
conn.close()
return order_id
Обновляем обработку корзины в handlers.py
Сделаем возможность корзины обновляться в реальном времени, а также у пользователя появятся кнопки «+» и «-» возле каждого товара.
@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
chat_id = event.message.chat.id if isinstance(event, CallbackQuery) else event.chat.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("❌ Ваша корзина пуста, добавьте товары перед заказом.")
✅ Теперь бот принимает номер телефона как через кнопку, так и вручную.
В итоге полный код handlers.py
должен быть такой:
from aiogram import Router, F
from aiogram.types import Message, CallbackQuery, ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton
from keyboards import main_menu
from database import get_products, add_to_cart, get_cart, create_order, remove_from_cart
router = Router()
# Обработчик команды /start
@router.message(F.text == "/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
chat_id = event.message.chat.id if isinstance(event, CallbackQuery) else event.chat.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("❌ Ваша корзина пуста, добавьте товары перед заказом.")
Тестируем новые функции
1️⃣ Удаляем старую базу и создаём новую.
2️⃣ Запускаем бота: python bot.py
3️⃣ Добавляем товары в корзину.
4️⃣ Пробуем «➕» и «➖» для изменения количества.
5️⃣ Нажимаем «🔄 Обновить корзину» и видим изменения сразу.
6️⃣ Оформляем заказ, отправляем номер телефона.
Заключение
Теперь Telegram-магазин полностью поддерживает:
✅ Управление количеством товаров в корзине.
✅ Автоматическое обновление корзины.
✅ Оформление заказа с подтверждением номера телефона.
🎉 В следующей статье мы создадим панель администратора! 🚀
Пока нет комментариев. Будьте первым!