This repository has been archived on 2026-02-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
events/bp/calendar_entry/services/ticket_operations.py
giles 3c0fa45f8c
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
feat: initialize events app with calendars, slots, tickets, and internal API
Extract events/calendar functionality into standalone microservice:
- app.py and events_api.py from apps/events/
- Calendar blueprints (calendars, calendar, calendar_entries, calendar_entry, day, slots, slot, ticket_types, ticket_type)
- Templates for all calendar/event views including admin
- Dockerfile (APP_MODULE=app:app, IMAGE=events)
- entrypoint.sh (no Alembic - migrations managed by blog app)
- Gitea CI workflow for build and deploy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 23:16:32 +00:00

88 lines
2.3 KiB
Python

from __future__ import annotations
from typing import Optional
from decimal import Decimal
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from models.calendars import CalendarEntry
async def update_ticket_config(
session: AsyncSession,
entry_id: int,
ticket_price: Optional[Decimal],
ticket_count: Optional[int],
) -> tuple[bool, Optional[str]]:
"""
Update ticket configuration for a calendar entry.
Args:
session: Database session
entry_id: Calendar entry ID
ticket_price: Price per ticket (None = no tickets)
ticket_count: Total available tickets (None = unlimited)
Returns:
(success, error_message)
"""
# Get the entry
entry = await session.scalar(
select(CalendarEntry).where(
CalendarEntry.id == entry_id,
CalendarEntry.deleted_at.is_(None)
)
)
if not entry:
return False, "Calendar entry not found"
# Validate inputs
if ticket_price is not None and ticket_price < 0:
return False, "Ticket price cannot be negative"
if ticket_count is not None and ticket_count < 0:
return False, "Ticket count cannot be negative"
# Update ticket configuration
entry.ticket_price = ticket_price
entry.ticket_count = ticket_count
return True, None
async def get_available_tickets(
session: AsyncSession,
entry_id: int,
) -> tuple[Optional[int], Optional[str]]:
"""
Get the number of available tickets for a calendar entry.
Returns:
(available_count, error_message)
- available_count is None if unlimited tickets
- available_count is the remaining count if limited
"""
entry = await session.scalar(
select(CalendarEntry).where(
CalendarEntry.id == entry_id,
CalendarEntry.deleted_at.is_(None)
)
)
if not entry:
return None, "Calendar entry not found"
# If no ticket configuration, return None (unlimited)
if entry.ticket_price is None:
return None, None
# If ticket_count is None, unlimited tickets
if entry.ticket_count is None:
return None, None
# TODO: Subtract booked tickets when ticket booking is implemented
# For now, just return the total count
return entry.ticket_count, None