Files
xenia-pos-local/local_backend/services/reservation_tasks.py
bonamin 79bd3b0f41 feat(local_backend): reservations, print analytics, workday summary, zone-PIN management
- New reservations module: model, schema, router (CRUD + status updates + upcoming alerts)
  and background task for auto-expiring stale reservations
- Reports: print_products, print_categories, print_tables analytics endpoints
  plus meta_products and business_day_summary for workday close/view flow
- printer_service: configurable font sizes/weights, donut/bar chart print layout helpers,
  analytics print blocks per printer
- tables/schemas: surfaced color, zone, and other new fields on Table, Product, User, Printer
- demo_seed.py for quick dev DB population; wipe_database.py utility

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 20:25:22 +03:00

49 lines
1.6 KiB
Python

"""Background task: auto-mark overdue pending reservations as no_show."""
import asyncio
import logging
from datetime import datetime, timezone, timedelta
logger = logging.getLogger(__name__)
# Grace period after reserved_for before a pending reservation becomes no_show
NO_SHOW_GRACE_MINUTES = 30
# How often the checker runs
CHECK_INTERVAL_SECONDS = 300 # 5 minutes
async def _run_no_show_checker():
# Import here to avoid circular imports at module load time
from database import SessionLocal
from models.reservation import Reservation
while True:
await asyncio.sleep(CHECK_INTERVAL_SECONDS)
try:
db = SessionLocal()
try:
cutoff = datetime.now(timezone.utc) - timedelta(minutes=NO_SHOW_GRACE_MINUTES)
overdue = (
db.query(Reservation)
.filter(
Reservation.status == "pending",
Reservation.reserved_for < cutoff,
)
.all()
)
if overdue:
for r in overdue:
r.status = "no_show"
r.updated_at = datetime.now(timezone.utc)
db.commit()
logger.info("no_show_checker: marked %d reservation(s) as no_show", len(overdue))
finally:
db.close()
except Exception:
logger.exception("no_show_checker: unexpected error")
async def start_reservation_tasks() -> asyncio.Task:
task = asyncio.create_task(_run_no_show_checker())
return task