Add ticket +/- quantity support to shared contracts and services

- Add ticket_type_id field to TicketDTO for grouping
- Add adjust_ticket_quantity to CalendarService protocol + SQL impl
- Add stub for adjust_ticket_quantity

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-21 08:53:04 +00:00
parent e83df2f742
commit 1f8fb521b2
4 changed files with 69 additions and 0 deletions

View File

@@ -72,6 +72,7 @@ def _ticket_to_dto(ticket: Ticket) -> TicketDTO:
created_at=ticket.created_at,
checked_in_at=ticket.checked_in_at,
entry_id=entry.id if entry else None,
ticket_type_id=ticket.ticket_type_id,
price=price,
order_id=ticket.order_id,
calendar_container_id=cal.container_id if cal else None,
@@ -563,3 +564,59 @@ class SqlCalendarService:
)
for ticket in result.scalars().all():
ticket.user_id = user_id
async def adjust_ticket_quantity(
self, session: AsyncSession, entry_id: int, count: int, *,
user_id: int | None, session_id: str | None,
ticket_type_id: int | None = None,
) -> int:
"""Adjust reserved ticket count to target. Returns new count."""
import uuid
count = max(count, 0)
# Current reserved count
filters = [
Ticket.entry_id == entry_id,
Ticket.state == "reserved",
]
if user_id is not None:
filters.append(Ticket.user_id == user_id)
elif session_id is not None:
filters.append(Ticket.session_id == session_id)
else:
return 0
if ticket_type_id is not None:
filters.append(Ticket.ticket_type_id == ticket_type_id)
current = await session.scalar(
select(func.count(Ticket.id)).where(*filters)
) or 0
if count > current:
# Create tickets
for _ in range(count - current):
ticket = Ticket(
entry_id=entry_id,
ticket_type_id=ticket_type_id,
user_id=user_id,
session_id=session_id,
code=uuid.uuid4().hex,
state="reserved",
)
session.add(ticket)
await session.flush()
elif count < current:
# Cancel newest tickets
to_cancel = current - count
result = await session.execute(
select(Ticket)
.where(*filters)
.order_by(Ticket.created_at.desc())
.limit(to_cancel)
)
for ticket in result.scalars().all():
ticket.state = "cancelled"
await session.flush()
return count

View File

@@ -132,6 +132,11 @@ class StubCalendarService:
) -> None:
pass
async def adjust_ticket_quantity(
self, session, entry_id, count, *, user_id, session_id, ticket_type_id=None,
) -> int:
return 0
async def entry_ids_for_content(self, session, content_type, content_id):
return set()