Fix: Prevent cancellation of past appointments
Add check to both user and admin cancel endpoints to reject cancellation of appointments whose slot_start is in the past. This matches the spec requirement that cancellations can only happen 'before the appointment'. Added tests for both user and admin cancel endpoints. Also includes frontend styling updates.
This commit is contained in:
parent
89eec1e9c4
commit
63cf46c230
5 changed files with 679 additions and 291 deletions
|
|
@ -3,9 +3,11 @@ Booking API Tests
|
|||
|
||||
Tests for the user booking endpoints.
|
||||
"""
|
||||
from datetime import date, timedelta
|
||||
from datetime import date, datetime, timedelta, timezone
|
||||
import pytest
|
||||
|
||||
from models import Appointment, AppointmentStatus
|
||||
|
||||
|
||||
def tomorrow() -> date:
|
||||
return date.today() + timedelta(days=1)
|
||||
|
|
@ -656,6 +658,30 @@ class TestCancelAppointment:
|
|||
)
|
||||
assert len(slots_response.json()["slots"]) == 2
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cannot_cancel_past_appointment(self, client_factory, regular_user):
|
||||
"""User cannot cancel a past appointment."""
|
||||
# Create a past appointment directly in DB
|
||||
async with client_factory.get_db_session() as db:
|
||||
past_time = datetime.now(timezone.utc) - timedelta(hours=1)
|
||||
appointment = Appointment(
|
||||
user_id=regular_user["user"]["id"],
|
||||
slot_start=past_time,
|
||||
slot_end=past_time + timedelta(minutes=15),
|
||||
status=AppointmentStatus.BOOKED,
|
||||
)
|
||||
db.add(appointment)
|
||||
await db.commit()
|
||||
await db.refresh(appointment)
|
||||
apt_id = appointment.id
|
||||
|
||||
# Try to cancel
|
||||
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
||||
response = await client.post(f"/api/appointments/{apt_id}/cancel")
|
||||
|
||||
assert response.status_code == 400
|
||||
assert "past" in response.json()["detail"].lower()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Admin Appointments Tests
|
||||
|
|
@ -806,3 +832,27 @@ class TestAdminCancelAppointment:
|
|||
assert response.status_code == 400
|
||||
assert "cancelled_by_user" in response.json()["detail"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_cannot_cancel_past_appointment(self, client_factory, regular_user, admin_user):
|
||||
"""Admin cannot cancel a past appointment."""
|
||||
# Create a past appointment directly in DB
|
||||
async with client_factory.get_db_session() as db:
|
||||
past_time = datetime.now(timezone.utc) - timedelta(hours=1)
|
||||
appointment = Appointment(
|
||||
user_id=regular_user["user"]["id"],
|
||||
slot_start=past_time,
|
||||
slot_end=past_time + timedelta(minutes=15),
|
||||
status=AppointmentStatus.BOOKED,
|
||||
)
|
||||
db.add(appointment)
|
||||
await db.commit()
|
||||
await db.refresh(appointment)
|
||||
apt_id = appointment.id
|
||||
|
||||
# Admin tries to cancel
|
||||
async with client_factory.create(cookies=admin_user["cookies"]) as admin_client:
|
||||
response = await admin_client.post(f"/api/admin/appointments/{apt_id}/cancel")
|
||||
|
||||
assert response.status_code == 400
|
||||
assert "past" in response.json()["detail"].lower()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue