Добавлен полноценный сценарий записи
- выбор услуги через inline-кнопки - выбор даты через календарь - выбор времени через кнопки - подтверждение записи - отмена записи - редактирование записи - сохранение времени записи - исправлена работа FSM - исправлены callback-обработчики - улучшен интерфейс бота
This commit is contained in:
+148
-65
@@ -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()
|
||||||
)
|
)
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
|
)
|
||||||
@@ -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"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -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"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -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
|
||||||
|
)
|
||||||
@@ -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
|
||||||
@@ -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()
|
||||||
Reference in New Issue
Block a user