diff --git a/app/handlers/booking.py b/app/handlers/booking.py index 2e22482..de95cc5 100644 --- a/app/handlers/booking.py +++ b/app/handlers/booking.py @@ -10,7 +10,9 @@ from app.states.booking import BookingState from app.services.booking_service import ( create_booking, update_booking, - get_busy_times + get_busy_times, + is_slot_busy, + cleanup_cancelled ) from app.keyboards.menu import menu, cancel_menu from app.keyboards.calendar import get_dates_keyboard @@ -210,14 +212,31 @@ async def confirm_booking_callback( else: + # Check if slot is already taken + master = data.get('master', '?') + date = data.get('date', '?') + time = data.get('time', '?') + + if await is_slot_busy(master, date, time): + logger.warning("Slot already busy: {mst} {dt} {tm}", mst=master, dt=date, tm=time) + await callback.message.edit_text( + "❌ Это время уже занято. Пожалуйста, выберите другое время." + ) + await state.clear() + await callback.answer() + return + await create_booking( user_id=callback.from_user.id, service=data.get('service', '?'), - master=data.get('master', '?'), - date=data.get('date', '?'), - time=data.get('time', '?') + master=master, + date=date, + time=time ) + # Clean up old cancelled bookings + cleanup_cancelled() + result_text = "✅ Запись успешно создана" await state.clear() diff --git a/app/services/booking_service.py b/app/services/booking_service.py index 42538cb..f2d4874 100644 --- a/app/services/booking_service.py +++ b/app/services/booking_service.py @@ -4,7 +4,11 @@ from app.db.memory import ( get_user_bookings as db_get_user_bookings, cancel_booking as db_cancel_booking, update_booking as db_update_booking, + load_bookings as db_load_bookings, + save_bookings as db_save_bookings, + BOOKINGS_FILE, ) +from app.logger import logger async def create_booking(user_id, service, master, date, time): @@ -25,3 +29,36 @@ async def cancel_booking(booking_id): async def update_booking(booking_id, service, master, date, time): return db_update_booking(booking_id, service, master, date, time) + + +async def is_slot_busy(master, date, time): + """Check if a time slot is already taken by an active booking.""" + busy = db_get_busy_times(master, date) + return time in busy + + +def cleanup_cancelled(): + """Remove cancelled bookings older than the head (keep only last 5 cancelled per user).""" + bookings = db_load_bookings() + active = [b for b in bookings if b["status"] == "active"] + cancelled = [b for b in bookings if b["status"] == "cancelled"] + + # Group cancelled by user, keep last 5 per user + from collections import defaultdict + by_user = defaultdict(list) + for b in cancelled: + by_user[b["user_id"]].append(b) + + keep_ids = set() + for uid, user_cancel in by_user.items(): + # Keep the 5 most recent + user_cancel.sort(key=lambda x: x.get("id", 0), reverse=True) + for b in user_cancel[:5]: + keep_ids.add(b["id"]) + + # Rebuild: keep active + keep recent cancelled + bookings = active + [b for b in cancelled if b["id"] in keep_ids] + db_save_bookings(bookings) + removed = len(cancelled) - len(keep_ids) + if removed > 0: + logger.info("Cleaned up {n} old cancelled bookings", n=removed)