Добавлен полноценный сценарий записи

- выбор услуги через inline-кнопки
- выбор даты через календарь
- выбор времени через кнопки
- подтверждение записи
- отмена записи
- редактирование записи
- сохранение времени записи
- исправлена работа FSM
- исправлены callback-обработчики
- улучшен интерфейс бота
This commit is contained in:
grigorij
2026-06-13 19:51:11 +04:00
parent 34b2880a68
commit 9282c1bbfb
8 changed files with 274 additions and 68 deletions
+148 -65
View File
@@ -1,11 +1,17 @@
import re
from aiogram import Router, F from aiogram import Router, F
from aiogram.types import Message
from aiogram.fsm.context import FSMContext from aiogram.fsm.context import FSMContext
from aiogram.filters import StateFilter from aiogram.filters import StateFilter
from aiogram.types import Message, CallbackQuery
from app.keyboards.services import get_services_keyboard
from app.states.booking import BookingState from app.states.booking import BookingState
from app.services.booking_service import create_booking from app.services.booking_service import create_booking
from app.keyboards.menu import menu, cancel_menu from app.keyboards.menu import menu, cancel_menu
from app.keyboards.calendar import get_dates_keyboard
from app.keyboards.time_slots import get_time_keyboard
from app.keyboards.confirm_booking import get_confirm_booking_keyboard
router = Router() router = Router()
@@ -28,95 +34,172 @@ async def start_booking(message: Message, state: FSMContext):
await state.set_state(BookingState.service) await state.set_state(BookingState.service)
await message.answer( await message.answer(
"Выберите услугу:\n" "Выберите услугу:",
"1. Массаж\n" reply_markup=get_services_keyboard()
"2. SPA\n"
"3. Косметология",
reply_markup=cancel_menu
) )
# выбор услуги @router.callback_query(
@router.message(StateFilter(BookingState.service)) StateFilter(BookingState.service),
async def choose_service(message: Message, state: FSMContext): F.data.startswith("service_")
)
async def choose_service(
callback: CallbackQuery,
state: FSMContext
):
services = {
"service_massage": "Массаж",
"service_spa": "SPA",
"service_cosmetology": "Косметология"
}
forbidden = [ service_name = services[callback.data]
"📅 Записаться",
"👤 Профиль",
"📖 Мои записи",
"О компании",
"📞 Контакты"
]
if message.text in forbidden: await state.update_data(
await message.answer( service=service_name
"⚠️ Сначала завершите запись или напишите 'отмена'"
)
return
await state.update_data(service=message.text)
await state.set_state(BookingState.date)
await message.answer(
"Введите дату (например 20.06)"
) )
await state.set_state(
BookingState.date
)
await callback.message.edit_text(
"📅 Выберите дату:",
reply_markup=get_dates_keyboard()
)
await callback.answer()
# выбор даты # выбор даты
@router.message(StateFilter(BookingState.date)) @router.callback_query(
async def choose_date(message: Message, state: FSMContext): StateFilter(BookingState.date),
F.data.startswith("date_")
)
async def choose_date(
callback: CallbackQuery,
state: FSMContext
):
selected_date = callback.data.replace(
"date_",
""
)
forbidden = [ await state.update_data(
"📅 Записаться", date=selected_date
"👤 Профиль", )
"📖 Мои записи",
"О компании",
"📞 Контакты"
]
if message.text in forbidden: await state.set_state(
await message.answer( BookingState.time
"⚠️ Сначала завершите запись или напишите 'отмена'" )
)
return
await state.update_data(date=message.text) await callback.message.edit_text(
"🕒 Выберите время:",
reply_markup=get_time_keyboard()
)
await callback.answer()
@router.callback_query(
StateFilter(BookingState.time),
F.data.startswith("time_")
)
async def choose_time(
callback: CallbackQuery,
state: FSMContext
):
selected_time = callback.data.replace(
"time_",
""
)
await state.update_data(
time=selected_time
)
data = await state.get_data() data = await state.get_data()
await state.set_state(BookingState.confirm) await state.set_state(
BookingState.confirm
await message.answer(
f"Услуга: {data['service']}\n"
f"Дата: {data['date']}\n\n"
f"Напишите 'да' для подтверждения"
) )
await callback.message.edit_text(
f"📋 Проверьте запись:\n\n"
f"💆 Услуга: {data['service']}\n"
f"📅 Дата: {data['date']}\n"
f"🕒 Время: {selected_time}",
reply_markup=get_confirm_booking_keyboard()
)
await callback.answer()
# подтверждение # подтверждение
@router.message(StateFilter(BookingState.confirm)) @router.callback_query(
async def confirm_booking(message: Message, state: FSMContext): StateFilter(BookingState.confirm),
F.data == "confirm_booking"
if message.text.lower() != "да": )
await state.clear() async def confirm_booking_callback(
callback: CallbackQuery,
await message.answer( state: FSMContext
"❌ Запись отменена", ):
reply_markup=menu
)
data = await state.get_data() data = await state.get_data()
create_booking( create_booking(
user_id=message.from_user.id, user_id=callback.from_user.id,
service=data["service"], service=data["service"],
date=data["date"] date=data["date"],
time=data["time"]
) )
await state.clear() await state.clear()
await message.answer( await callback.message.edit_text(
"Вы успешно записаны!", "Запись успешно создана"
reply_markup=menu )
await callback.answer()
@router.callback_query(
StateFilter(BookingState.confirm),
F.data == "cancel_booking"
)
async def cancel_booking_callback(
callback: CallbackQuery,
state: FSMContext
):
await state.clear()
await callback.message.edit_text(
"❌ Запись отменена"
)
await callback.answer()
@router.callback_query(
StateFilter(BookingState.confirm),
F.data == "edit_booking"
)
async def edit_booking_callback(
callback: CallbackQuery,
state: FSMContext
):
old_data = await state.get_data()
await state.clear()
await state.update_data(
service=old_data.get("service")
)
await state.set_state(
BookingState.service
)
from app.keyboards.services import get_services_keyboard
await callback.message.edit_text(
"Выберите услугу:",
reply_markup=get_services_keyboard()
) )
+5 -1
View File
@@ -23,6 +23,10 @@ async def my_bookings(message: Message, state: FSMContext):
text = "📖 Ваши записи:\n\n" text = "📖 Ваши записи:\n\n"
for b in user_bookings: for b in user_bookings:
text += f"💆 {b['service']} — 📅 {b['date']}\n" text += (
f"💆 {b['service']}\n"
f"📅 {b['date']}\n"
f"🕒 {b['time']}\n\n"
)
await message.answer(text) await message.answer(text)
+24
View File
@@ -0,0 +1,24 @@
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from datetime import datetime, timedelta
def get_dates_keyboard():
buttons = []
today = datetime.now()
for i in range(7):
day = today + timedelta(days=i)
buttons.append(
[
InlineKeyboardButton(
text=day.strftime("%d.%m"),
callback_data=f"date_{day.strftime('%d.%m')}"
)
]
)
return InlineKeyboardMarkup(
inline_keyboard=buttons
)
+28
View File
@@ -0,0 +1,28 @@
from aiogram.types import InlineKeyboardMarkup
from aiogram.types import InlineKeyboardButton
def get_confirm_booking_keyboard():
return InlineKeyboardMarkup(
inline_keyboard=[
[
InlineKeyboardButton(
text="✅ Подтвердить",
callback_data="confirm_booking"
)
],
[
InlineKeyboardButton(
text="✏️ Изменить",
callback_data="edit_booking"
)
],
[
InlineKeyboardButton(
text="❌ Отменить",
callback_data="cancel_booking"
)
]
]
)
+28
View File
@@ -0,0 +1,28 @@
from aiogram.types import InlineKeyboardMarkup
from aiogram.types import InlineKeyboardButton
def get_services_keyboard():
return InlineKeyboardMarkup(
inline_keyboard=[
[
InlineKeyboardButton(
text="💆 Массаж",
callback_data="service_massage"
)
],
[
InlineKeyboardButton(
text="🌿 SPA",
callback_data="service_spa"
)
],
[
InlineKeyboardButton(
text="✨ Косметология",
callback_data="service_cosmetology"
)
]
]
)
+30
View File
@@ -0,0 +1,30 @@
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
def get_time_keyboard():
times = [
"10:00",
"11:00",
"12:00",
"13:00",
"14:00",
"15:00",
"16:00"
]
buttons = []
for t in times:
buttons.append(
[
InlineKeyboardButton(
text=t,
callback_data=f"time_{t}"
)
]
)
return InlineKeyboardMarkup(
inline_keyboard=buttons
)
+9 -1
View File
@@ -1,12 +1,20 @@
from app.db.memory import bookings from app.db.memory import bookings
def create_booking(user_id: int, service: str, date: str):
def create_booking(
user_id: int,
service: str,
date: str,
time: str
):
booking = { booking = {
"user_id": user_id, "user_id": user_id,
"service": service, "service": service,
"date": date, "date": date,
"time": time,
"status": "active" "status": "active"
} }
bookings.append(booking) bookings.append(booking)
return booking return booking
+1
View File
@@ -3,4 +3,5 @@ from aiogram.fsm.state import StatesGroup, State
class BookingState(StatesGroup): class BookingState(StatesGroup):
service = State() service = State()
date = State() date = State()
time = State()
confirm = State() confirm = State()