Files
azionelab/backend/checkins/test_services.py

198 lines
7.7 KiB
Python

from datetime import timedelta
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.utils import timezone
from bookings.models import Reservation, ReservationToken
from checkins.models import CheckIn
from checkins.services import (
AlreadyCheckedIn,
InvalidToken,
MissingStaffUser,
ReservationNotConfirmed,
confirm_check_in_for_reservation,
confirm_check_in_from_token,
preview_check_in_token,
)
from shows.models import Performance, Show, Venue
class CheckInServiceTests(TestCase):
def setUp(self):
self.show = Show.objects.create(
title="Open Stage",
slug="open-stage-checkins",
is_published=True,
)
self.venue = Venue.objects.create(
name="AzioneLab Theatre",
slug="azionelab-theatre-checkins",
address="Via Example 1",
city="Rome",
)
self.performance = Performance.objects.create(
show=self.show,
venue=self.venue,
starts_at=timezone.now() + timedelta(days=7),
room_capacity=20,
)
self.staff_user = get_user_model().objects.create_user(
username="staff",
password="test",
is_staff=True,
)
def test_successful_preview_returns_minimum_admission_data(self):
reservation = self.create_reservation()
_, raw_token = self.create_check_in_token(reservation)
preview = preview_check_in_token(raw_token, staff_user=self.staff_user)
self.assertEqual(preview.reservation_id, reservation.id)
self.assertEqual(preview.performance_id, self.performance.id)
self.assertEqual(preview.show_title, self.show.title)
self.assertEqual(preview.venue_name, self.venue.name)
self.assertEqual(preview.party_size, reservation.party_size)
self.assertFalse(preview.checked_in)
self.assertFalse(hasattr(preview, "name"))
self.assertFalse(hasattr(preview, "email"))
self.assertFalse(hasattr(preview, "phone"))
def test_preview_fails_for_invalid_token(self):
with self.assertRaises(InvalidToken):
preview_check_in_token("invalid-token", staff_user=self.staff_user)
def test_preview_rejects_confirmation_token_even_for_confirmed_reservation(self):
reservation = self.create_reservation()
_, raw_token = ReservationToken.create_token(
reservation=reservation,
purpose=ReservationToken.Purpose.CONFIRMATION,
expires_at=timezone.now() + timedelta(hours=2),
)
with self.assertRaises(InvalidToken):
preview_check_in_token(raw_token, staff_user=self.staff_user)
def test_preview_rejects_expired_check_in_token(self):
reservation = self.create_reservation()
_, raw_token = ReservationToken.create_token(
reservation=reservation,
purpose=ReservationToken.Purpose.CHECK_IN,
expires_at=timezone.now() - timedelta(minutes=1),
)
with self.assertRaises(InvalidToken):
preview_check_in_token(raw_token, staff_user=self.staff_user)
def test_check_in_succeeds_for_confirmed_reservation(self):
reservation = self.create_reservation()
_, raw_token = self.create_check_in_token(reservation)
result = confirm_check_in_from_token(raw_token, staff_user=self.staff_user)
self.assertEqual(result.check_in.reservation, reservation)
self.assertEqual(result.check_in.checked_in_by, self.staff_user)
self.assertEqual(result.check_in.source, CheckIn.Source.QR_SCAN)
self.assertTrue(result.preview.checked_in)
def test_check_in_fails_for_pending_reservation(self):
reservation = self.create_reservation(status=Reservation.Status.PENDING, confirmed_at=None)
_, raw_token = self.create_check_in_token(reservation)
with self.assertRaises(ReservationNotConfirmed):
confirm_check_in_from_token(raw_token, staff_user=self.staff_user)
self.assertFalse(CheckIn.objects.filter(reservation=reservation).exists())
def test_duplicate_check_in_fails(self):
reservation = self.create_reservation()
_, raw_token = self.create_check_in_token(reservation)
confirm_check_in_from_token(raw_token, staff_user=self.staff_user)
with self.assertRaises(AlreadyCheckedIn):
confirm_check_in_from_token(raw_token, staff_user=self.staff_user)
self.assertEqual(CheckIn.objects.filter(reservation=reservation).count(), 1)
def test_check_in_stores_timestamp_and_staff_user(self):
reservation = self.create_reservation()
_, raw_token = self.create_check_in_token(reservation)
before_check_in = timezone.now()
result = confirm_check_in_from_token(
raw_token,
staff_user=self.staff_user,
source=CheckIn.Source.MANUAL,
)
self.assertGreaterEqual(result.check_in.checked_in_at, before_check_in)
self.assertEqual(result.check_in.checked_in_by, self.staff_user)
self.assertEqual(result.check_in.source, CheckIn.Source.MANUAL)
def test_check_in_requires_staff_user(self):
reservation = self.create_reservation()
_, raw_token = self.create_check_in_token(reservation)
with self.assertRaises(MissingStaffUser):
confirm_check_in_from_token(raw_token, staff_user=None)
def test_manual_check_in_by_reservation_id_succeeds_for_confirmed_reservation(self):
reservation = self.create_reservation()
result = confirm_check_in_for_reservation(
reservation_id=reservation.id,
staff_user=self.staff_user,
)
self.assertEqual(result.check_in.reservation, reservation)
self.assertEqual(result.check_in.checked_in_by, self.staff_user)
self.assertEqual(result.check_in.source, CheckIn.Source.MANUAL)
def test_manual_check_in_by_reservation_id_rejects_pending_reservation(self):
reservation = self.create_reservation(status=Reservation.Status.PENDING, confirmed_at=None)
with self.assertRaises(ReservationNotConfirmed):
confirm_check_in_for_reservation(
reservation_id=reservation.id,
staff_user=self.staff_user,
)
def test_check_in_rejects_confirmation_token_even_for_confirmed_reservation(self):
reservation = self.create_reservation()
_, raw_token = ReservationToken.create_token(
reservation=reservation,
purpose=ReservationToken.Purpose.CONFIRMATION,
expires_at=timezone.now() + timedelta(hours=2),
)
with self.assertRaises(InvalidToken):
confirm_check_in_from_token(raw_token, staff_user=self.staff_user)
def test_check_in_rejects_used_check_in_token(self):
reservation = self.create_reservation()
token, raw_token = self.create_check_in_token(reservation)
token.mark_used()
with self.assertRaises(InvalidToken):
confirm_check_in_from_token(raw_token, staff_user=self.staff_user)
def create_reservation(self, **overrides):
data = {
"performance": self.performance,
"name": "Maria Rossi",
"email": "maria@example.com",
"party_size": 2,
"status": Reservation.Status.CONFIRMED,
"confirmed_at": timezone.now(),
}
data.update(overrides)
return Reservation.objects.create(**data)
def create_check_in_token(self, reservation):
return ReservationToken.create_token(
reservation=reservation,
purpose=ReservationToken.Purpose.CHECK_IN,
expires_at=self.performance.starts_at + timedelta(days=1),
)