from django.contrib.auth import get_user_model from django.test import TestCase from django.utils import timezone from apps.accounts.models import Customer from apps.core.errors import ApiError from apps.reservations.models import Facility, Slot from apps.reservations.services import ReservationService User = get_user_model() class ReservationTests(TestCase): def setUp(self): self.user = User.objects.create_user(username="c1", password="x") self.customer = Customer.objects.create(user=self.user) self.facility = Facility.objects.create(name="F1") self.slot = Slot.objects.create( facility=self.facility, date=timezone.localdate(), start_time="08:00", end_time="08:30", capacity=1, ) self.service = ReservationService() def test_double_booking_prevented(self): self.service.book(self.customer, self.slot) with self.assertRaises(ApiError) as ctx: self.service.book(self.customer, self.slot) self.assertEqual(ctx.exception.code, "SLOT_FULL") def test_cancel_frees_slot(self): reservation = self.service.book(self.customer, self.slot) self.service.cancel(reservation) self.slot.refresh_from_db() self.assertEqual(self.slot.booked_count, 0) def test_cannot_book_blocked_slot(self): self.slot.blocked = True self.slot.save() with self.assertRaises(ApiError) as ctx: self.service.book(self.customer, self.slot) self.assertEqual(ctx.exception.code, "SLOT_BLOCKED") def test_generate_slots_from_dynamic_settings(self): from apps.core.settings_service import SettingsService from apps.reservations.slot_service import SlotService facility2 = Facility.objects.create(name="F2") svc = SettingsService() svc.set("reservation.working_hours_start", "08:00") svc.set("reservation.working_hours_end", "09:00") svc.set("reservation.slot_duration_minutes", 30) svc.set("reservation.default_capacity", 3) created = SlotService().generate_slots(facility2, timezone.localdate()) self.assertEqual(created, 2) slots = Slot.objects.filter(facility=facility2).order_by("start_time") self.assertEqual(slots.count(), 2) self.assertEqual(slots.first().capacity, 3) self.assertEqual(str(slots.first().end_time), "08:30:00") def test_day_off_generates_no_slots(self): from apps.reservations.models import FacilitySchedule from apps.reservations.slot_service import SlotService facility3 = Facility.objects.create(name="F3") FacilitySchedule.objects.create(facility=facility3, date=timezone.localdate(), is_open=False) created = SlotService().generate_slots(facility3, timezone.localdate()) self.assertEqual(created, 0) def test_approve_sends_sms(self): from apps.notifications.models import NotificationLog, NotificationTemplate NotificationTemplate.objects.create(event="reservation.approved", channel="sms", body="Hi {{customer_name}}") reservation = self.service.book(self.customer, self.slot, title="Batch A") self.assertEqual(reservation.status, "pending") self.service.approve(reservation, self.user) reservation.refresh_from_db() self.assertEqual(reservation.status, "confirmed") self.assertEqual(NotificationLog.objects.filter(status="sent").count(), 1)