fix(models): restore check_in/check_out on AvailabilityQuery

v0.4.0's merge of public_booking_dict landed inside AvailabilityQuery and
left the two date fields orphaned after the helper's return, so
POST /api/v1/availability raised AttributeError on q.check_in (500) on
every install of that version. The RPC door reads the raw body and was
unaffected, which is why nothing noticed.

Put the helper next to public_room_dict and add a regression test that
constructs the query model and drives the endpoint through the
services layer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-09-16 11:42:43 +02:00
commit 64607a00bc
2 changed files with 60 additions and 4 deletions

View file

@ -206,8 +206,6 @@ def public_room_dict(room: Room) -> dict:
return d
class AvailabilityQuery(BaseModel):
room_id: str
def public_booking_dict(booking: "Booking") -> dict:
"""A Booking as public JSON for the guest who holds its id — lifecycle +
money + dates only. Strips the guest's own identity/contact (so the id
@ -227,8 +225,10 @@ def public_booking_dict(booking: "Booking") -> dict:
return d
check_in: str # YYYY-MM-DD inclusive
check_out: str # YYYY-MM-DD exclusive
class AvailabilityQuery(BaseModel):
room_id: str
check_in: str # YYYY-MM-DD inclusive
check_out: str # YYYY-MM-DD exclusive
class AvailabilityResult(BaseModel):

View file

@ -0,0 +1,56 @@
"""Guest availability endpoint. Regression guard for v0.4.0, where a bad merge
left AvailabilityQuery with only `room_id` and POST /availability 500'd on
`q.check_in` — the RPC door reads the raw body, so only HTTP was broken and no
test exercised it."""
import asyncio
import pytest
from fastapi import HTTPException
from pydantic import ValidationError
from .. import services, views_api
from ..models import AvailabilityQuery, AvailabilityResult
def test_availability_query_requires_both_dates():
q = AvailabilityQuery(room_id="r", check_in="2026-10-01", check_out="2026-10-03")
assert (q.room_id, q.check_in, q.check_out) == ("r", "2026-10-01", "2026-10-03")
assert set(AvailabilityQuery.__fields__) == {"room_id", "check_in", "check_out"}
with pytest.raises(ValidationError):
AvailabilityQuery(room_id="r") # type: ignore[call-arg]
def test_availability_endpoint_forwards_all_three_fields(monkeypatch):
seen: list[tuple] = []
async def fake(room_id, check_in, check_out):
seen.append((room_id, check_in, check_out))
return AvailabilityResult(
room_id=room_id,
check_in=check_in,
check_out=check_out,
available=True,
nights=2,
)
monkeypatch.setattr(services, "get_availability", fake)
q = AvailabilityQuery(room_id="r", check_in="2026-10-01", check_out="2026-10-03")
out = asyncio.run(views_api.api_check_availability(q))
assert seen == [("r", "2026-10-01", "2026-10-03")]
assert out.available and out.nights == 2
@pytest.mark.parametrize(
("exc", "status"),
[(services.NotFound("Room not found"), 404), (ValueError("bad dates"), 400)],
)
def test_availability_endpoint_maps_service_errors(monkeypatch, exc, status):
async def fake(*_):
raise exc
monkeypatch.setattr(services, "get_availability", fake)
q = AvailabilityQuery(room_id="r", check_in="2026-10-03", check_out="2026-10-01")
with pytest.raises(HTTPException) as e:
asyncio.run(views_api.api_check_availability(q))
assert e.value.status_code == status