yeswanth0212/token_system
1
1# pyrefly: ignore [missing-import]2from fastapi import FastAPI, Depends, HTTPException3from fastapi.middleware.cors import CORSMiddleware4from fastapi.responses import StreamingResponse, FileResponse5from fastapi.staticfiles import StaticFiles6from sqlalchemy.orm import Session7from pydantic import BaseModel8from typing import Optional9import io10import csv11import crud, models, schemas12from database import engine, get_db13 14models.Base.metadata.create_all(bind=engine)15 16app = FastAPI(title="Clinic Token System API")17 18app.add_middleware(19 CORSMiddleware,20 allow_origins=["http://localhost:3000", "http://127.0.0.1:3000", "http://localhost:8080", "http://127.0.0.1:8080", "*"],21 allow_credentials=True,22 allow_methods=["*"],23 allow_headers=["*"],24)25 26class CounterStatusUpdate(BaseModel):27 status: str28 supported_departments: Optional[str] = None29 30@app.post("/api/tokens", response_model=schemas.TokenBase)31def create_token(token: schemas.TokenCreate, db: Session = Depends(get_db)):32 return crud.create_token(db=db, token=token)33 34@app.get("/api/queue", response_model=schemas.QueueStatus)35def read_queue(db: Session = Depends(get_db)):36 return crud.get_queue_status(db)37 38@app.put("/api/counters/{counter_id}/call", response_model=schemas.TokenBase)39def call_next(counter_id: int, db: Session = Depends(get_db)):40 token = crud.call_next_token(db, counter_id)41 if not token:42 raise HTTPException(status_code=404, detail="No waiting tokens found for this counter")43 return token44 45@app.put("/api/counters/{counter_id}/complete", response_model=schemas.TokenBase)46def complete_current(counter_id: int, db: Session = Depends(get_db)):47 token = crud.complete_token(db, counter_id)48 if not token:49 raise HTTPException(status_code=404, detail="Counter not serving any token")50 return token51 52@app.put("/api/counters/{counter_id}/skip", response_model=schemas.TokenBase)53def skip_current(counter_id: int, db: Session = Depends(get_db)):54 token = crud.skip_token(db, counter_id)55 if not token:56 raise HTTPException(status_code=404, detail="Counter not serving any token to skip")57 return token58 59@app.put("/api/counters/{counter_id}/status", response_model=schemas.ServiceCounterBase)60def update_counter_status(counter_id: int, update_data: CounterStatusUpdate, db: Session = Depends(get_db)):61 counter = crud.update_counter(62 db=db, 63 counter_id=counter_id, 64 status=update_data.status, 65 supported_departments=update_data.supported_departments66 )67 if not counter:68 raise HTTPException(status_code=404, detail="Counter not found")69 return counter70 71@app.get("/api/analytics", response_model=schemas.AnalyticsSummary)72def get_analytics(db: Session = Depends(get_db)):73 return crud.get_analytics_summary(db)74 75@app.get("/api/analytics/export")76def export_csv(db: Session = Depends(get_db)):77 output = io.StringIO()78 writer = csv.writer(output)79 80 writer.writerow([81 "Token ID", "Token Number", "Patient Name", "Department", 82 "Priority Status", "Status", "Created At", "Served At", "Completed At"83 ])84 85 tokens = db.query(models.Token).order_by(models.Token.id.asc()).all()86 for t in tokens:87 writer.writerow([88 t.id, t.token_number, t.patient_name, t.department,89 "Priority" if t.priority else "Standard", t.status.value,90 t.created_at.strftime("%Y-%m-%d %H:%M:%S") if t.created_at else "",91 t.served_at.strftime("%Y-%m-%d %H:%M:%S") if t.served_at else "",92 t.completed_at.strftime("%Y-%m-%d %H:%M:%S") if t.completed_at else ""93 ])94 95 output.seek(0)96 return StreamingResponse(97 output, 98 media_type="text/csv", 99 headers={"Content-Disposition": "attachment; filename=clinic_tokens_report.csv"}100 )101 102@app.post("/api/reset")103def reset_database(db: Session = Depends(get_db)):104 # Clear tables105 db.query(models.Token).delete()106 db.query(models.ServiceCounter).delete()107 db.commit()108 109 # Recreate default counters110 counters = [111 models.ServiceCounter(name="Counter 1", status="active", supported_departments="All"),112 models.ServiceCounter(name="Counter 2", status="active", supported_departments="General, Pediatrics"),113 models.ServiceCounter(name="Counter 3", status="active", supported_departments="Cardiology, Dental"),114 models.ServiceCounter(name="Counter 4", status="paused", supported_departments="General")115 ]116 db.add_all(counters)117 db.commit()118 return {"message": "Database reset and seeded with default counters."}119 120# Mount the frontend directory to serve static files (style.css, app.jsx, index.html)121import os122frontend_path = os.path.join(os.path.dirname(__file__), "../frontend")123 124@app.get("/")125def serve_index():126 return FileResponse(os.path.join(frontend_path, "index.html"))127 128app.mount("/", StaticFiles(directory=frontend_path), name="frontend")129 