From 9282c1bbfb7f0ab65599774b4ed2d7e46d434572 Mon Sep 17 00:00:00 2001 From: grigorij Date: Sat, 13 Jun 2026 19:51:11 +0400 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BF=D0=BE=D0=BB=D0=BD=D0=BE=D1=86=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D1=81=D1=86=D0=B5=D0=BD=D0=B0=D1=80=D0=B8=D0=B9?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - выбор услуги через inline-кнопки - выбор даты через календарь - выбор времени через кнопки - подтверждение записи - отмена записи - редактирование записи - сохранение времени записи - исправлена работа FSM - исправлены callback-обработчики - улучшен интерфейс бота --- app/handlers/booking.py | 215 +++++++++++++++++++++---------- app/handlers/mybookings.py | 6 +- app/keyboards/calendar.py | 24 ++++ app/keyboards/confirm_booking.py | 28 ++++ app/keyboards/services.py | 28 ++++ app/keyboards/time_slots.py | 30 +++++ app/services/booking_service.py | 10 +- app/states/booking.py | 1 + 8 files changed, 274 insertions(+), 68 deletions(-) diff --git a/app/handlers/booking.py b/app/handlers/booking.py index f2afef0..cc08d39 100644 --- a/app/handlers/booking.py +++ b/app/handlers/booking.py @@ -1,11 +1,17 @@ +import re + from aiogram import Router, F -from aiogram.types import Message from aiogram.fsm.context import FSMContext 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.services.booking_service import create_booking 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() @@ -28,95 +34,172 @@ async def start_booking(message: Message, state: FSMContext): await state.set_state(BookingState.service) await message.answer( - "Выберите услугу:\n" - "1. Массаж\n" - "2. SPA\n" - "3. Косметология", - reply_markup=cancel_menu + "Выберите услугу:", + reply_markup=get_services_keyboard() ) -# выбор услуги -@router.message(StateFilter(BookingState.service)) -async def choose_service(message: Message, state: FSMContext): +@router.callback_query( + StateFilter(BookingState.service), + 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 message.answer( - "⚠️ Сначала завершите запись или напишите 'отмена'" - ) - return - - await state.update_data(service=message.text) - - await state.set_state(BookingState.date) - - await message.answer( - "Введите дату (например 20.06)" + await state.update_data( + service=service_name ) + await state.set_state( + BookingState.date + ) + await callback.message.edit_text( + "📅 Выберите дату:", + reply_markup=get_dates_keyboard() + ) + + await callback.answer() + # выбор даты -@router.message(StateFilter(BookingState.date)) -async def choose_date(message: Message, state: FSMContext): +@router.callback_query( + 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 message.answer( - "⚠️ Сначала завершите запись или напишите 'отмена'" - ) - return + await state.set_state( + BookingState.time + ) - 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() - await state.set_state(BookingState.confirm) - - await message.answer( - f"Услуга: {data['service']}\n" - f"Дата: {data['date']}\n\n" - f"Напишите 'да' для подтверждения" + await state.set_state( + BookingState.confirm ) + 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)) -async def confirm_booking(message: Message, state: FSMContext): - - if message.text.lower() != "да": - await state.clear() - - await message.answer( - "❌ Запись отменена", - reply_markup=menu - ) - +@router.callback_query( + StateFilter(BookingState.confirm), + F.data == "confirm_booking" +) +async def confirm_booking_callback( + callback: CallbackQuery, + state: FSMContext +): data = await state.get_data() create_booking( - user_id=message.from_user.id, + user_id=callback.from_user.id, service=data["service"], - date=data["date"] + date=data["date"], + time=data["time"] ) await state.clear() - await message.answer( - "✅ Вы успешно записаны!", - reply_markup=menu - ) \ No newline at end of file + await callback.message.edit_text( + "✅ Запись успешно создана" + ) + 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() + ) diff --git a/app/handlers/mybookings.py b/app/handlers/mybookings.py index cf560f3..13bc8a8 100644 --- a/app/handlers/mybookings.py +++ b/app/handlers/mybookings.py @@ -23,6 +23,10 @@ async def my_bookings(message: Message, state: FSMContext): text = "📖 Ваши записи:\n\n" 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) \ No newline at end of file diff --git a/app/keyboards/calendar.py b/app/keyboards/calendar.py index e69de29..1e02289 100644 --- a/app/keyboards/calendar.py +++ b/app/keyboards/calendar.py @@ -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 + ) \ No newline at end of file diff --git a/app/keyboards/confirm_booking.py b/app/keyboards/confirm_booking.py index e69de29..8f7a28a 100644 --- a/app/keyboards/confirm_booking.py +++ b/app/keyboards/confirm_booking.py @@ -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" + ) + ] + ] + ) \ No newline at end of file diff --git a/app/keyboards/services.py b/app/keyboards/services.py index e69de29..813ffbc 100644 --- a/app/keyboards/services.py +++ b/app/keyboards/services.py @@ -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" + ) + ] + ] + ) \ No newline at end of file diff --git a/app/keyboards/time_slots.py b/app/keyboards/time_slots.py index e69de29..9dc16e1 100644 --- a/app/keyboards/time_slots.py +++ b/app/keyboards/time_slots.py @@ -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 + ) \ No newline at end of file diff --git a/app/services/booking_service.py b/app/services/booking_service.py index fe182df..938ace9 100644 --- a/app/services/booking_service.py +++ b/app/services/booking_service.py @@ -1,12 +1,20 @@ 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 = { "user_id": user_id, "service": service, "date": date, + "time": time, "status": "active" } bookings.append(booking) + return booking \ No newline at end of file diff --git a/app/states/booking.py b/app/states/booking.py index 12e607a..9b31367 100644 --- a/app/states/booking.py +++ b/app/states/booking.py @@ -3,4 +3,5 @@ from aiogram.fsm.state import StatesGroup, State class BookingState(StatesGroup): service = State() date = State() + time = State() confirm = State() \ No newline at end of file