Files
azionelab/backend/checkins/test_api.py
2026-04-29 10:01:06 +02:00

191 lines
7.2 KiB
Python

from datetime import timedelta
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.utils import timezone
from rest_framework import status
from rest_framework.test import APITestCase
from bookings.models import Reservation, ReservationToken
from checkins.models import CheckIn
from shows.models import Performance, Show, Venue
class CheckInApiTests(APITestCase):
def setUp(self):
self.show = Show.objects.create(
title="Open Stage",
slug="open-stage-checkin-api",
is_published=True,
)
self.venue = Venue.objects.create(
name="AzioneLab Theatre",
slug="azionelab-theatre-checkin-api",
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-api",
password="test",
is_staff=True,
)
self.regular_user = get_user_model().objects.create_user(
username="regular-api",
password="test",
is_staff=False,
)
def test_preview_success_as_staff_user(self):
reservation = self.create_reservation()
_, raw_token = self.create_check_in_token(reservation)
self.client.force_authenticate(user=self.staff_user)
response = self.client.post(
reverse("api-check-in-preview"),
{"token": raw_token},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["status"], "valid")
self.assertEqual(response.data["reservation_id"], reservation.id)
self.assertEqual(response.data["performance_id"], self.performance.id)
self.assertEqual(response.data["show_title"], self.show.title)
self.assertEqual(response.data["party_size"], reservation.party_size)
self.assertNotIn("name", response.data)
self.assertNotIn("email", response.data)
self.assertNotIn("phone", response.data)
def test_preview_denied_for_anonymous_user(self):
reservation = self.create_reservation()
_, raw_token = self.create_check_in_token(reservation)
response = self.client.post(
reverse("api-check-in-preview"),
{"token": raw_token},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
def test_preview_fails_for_invalid_token(self):
self.client.force_authenticate(user=self.staff_user)
response = self.client.post(
reverse("api-check-in-preview"),
{"token": "invalid-token"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(response.data["status"], "invalid_token")
def test_check_in_success_as_staff_user(self):
reservation = self.create_reservation()
_, raw_token = self.create_check_in_token(reservation)
self.client.force_authenticate(user=self.staff_user)
response = self.client.post(
reverse("api-check-in-confirm"),
{"token": raw_token},
format="json",
)
check_in = CheckIn.objects.get(reservation=reservation)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["status"], "checked_in")
self.assertEqual(response.data["reservation_id"], reservation.id)
self.assertEqual(response.data["performance_id"], self.performance.id)
self.assertEqual(response.data["party_size"], reservation.party_size)
self.assertEqual(response.data["checked_in_by"], self.staff_user.id)
self.assertIsNotNone(response.data["checked_in_at"])
self.assertEqual(check_in.checked_in_by, self.staff_user)
def test_check_in_denied_for_anonymous_user(self):
reservation = self.create_reservation()
_, raw_token = self.create_check_in_token(reservation)
response = self.client.post(
reverse("api-check-in-confirm"),
{"token": raw_token},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
self.assertFalse(CheckIn.objects.filter(reservation=reservation).exists())
def test_check_in_denied_for_non_staff_authenticated_user(self):
reservation = self.create_reservation()
_, raw_token = self.create_check_in_token(reservation)
self.client.force_authenticate(user=self.regular_user)
response = self.client.post(
reverse("api-check-in-confirm"),
{"token": raw_token},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertFalse(CheckIn.objects.filter(reservation=reservation).exists())
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)
self.client.force_authenticate(user=self.staff_user)
response = self.client.post(
reverse("api-check-in-confirm"),
{"token": raw_token},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
self.assertEqual(response.data["status"], "reservation_not_confirmed")
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)
self.client.force_authenticate(user=self.staff_user)
first_response = self.client.post(
reverse("api-check-in-confirm"),
{"token": raw_token},
format="json",
)
second_response = self.client.post(
reverse("api-check-in-confirm"),
{"token": raw_token},
format="json",
)
self.assertEqual(first_response.status_code, status.HTTP_200_OK)
self.assertEqual(second_response.status_code, status.HTTP_409_CONFLICT)
self.assertEqual(second_response.data["status"], "already_checked_in")
self.assertEqual(CheckIn.objects.filter(reservation=reservation).count(), 1)
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),
)