Phase 1: scaffold local backend — models, schemas, routers, printer service, Docker

This commit is contained in:
2026-04-20 11:22:55 +03:00
commit 4ffe27df95
44 changed files with 2729 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
import bcrypt
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List
from database import get_db
from models.user import User, AssistantAssignment
from schemas.user import UserCreate, UserUpdate, UserOut, AssistantAssignmentOut
from routers.deps import require_manager
router = APIRouter()
class ResetPinRequest:
def __init__(self, pin: str):
self.pin = pin
@router.get("/", response_model=List[UserOut])
def list_waiters(db: Session = Depends(get_db), user: User = Depends(require_manager)):
return db.query(User).filter(User.role == "waiter").all()
@router.post("/", response_model=UserOut, status_code=status.HTTP_201_CREATED)
def create_waiter(body: UserCreate, db: Session = Depends(get_db), user: User = Depends(require_manager)):
if db.query(User).filter(User.username == body.username).first():
raise HTTPException(status_code=400, detail="Username already exists")
pin_hash = bcrypt.hashpw(body.pin.encode(), bcrypt.gensalt()).decode()
new_user = User(username=body.username, pin_hash=pin_hash, role=body.role, is_active=body.is_active)
db.add(new_user)
db.commit()
db.refresh(new_user)
return new_user
@router.put("/{waiter_id}", response_model=UserOut)
def update_waiter(waiter_id: int, body: UserUpdate, db: Session = Depends(get_db), user: User = Depends(require_manager)):
waiter = db.query(User).filter(User.id == waiter_id).first()
if not waiter:
raise HTTPException(status_code=404, detail="Waiter not found")
for field, value in body.model_dump(exclude_none=True).items():
setattr(waiter, field, value)
db.commit()
db.refresh(waiter)
return waiter
@router.put("/{waiter_id}/reset-pin")
def reset_pin(waiter_id: int, pin: str, db: Session = Depends(get_db), user: User = Depends(require_manager)):
waiter = db.query(User).filter(User.id == waiter_id).first()
if not waiter:
raise HTTPException(status_code=404, detail="Waiter not found")
waiter.pin_hash = bcrypt.hashpw(pin.encode(), bcrypt.gensalt()).decode()
db.commit()
return {"status": "pin reset"}
@router.put("/{waiter_id}/block")
def toggle_block(waiter_id: int, db: Session = Depends(get_db), user: User = Depends(require_manager)):
waiter = db.query(User).filter(User.id == waiter_id).first()
if not waiter:
raise HTTPException(status_code=404, detail="Waiter not found")
waiter.is_active = not waiter.is_active
db.commit()
return {"is_active": waiter.is_active}
@router.delete("/{waiter_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_waiter(waiter_id: int, db: Session = Depends(get_db), user: User = Depends(require_manager)):
waiter = db.query(User).filter(User.id == waiter_id).first()
if not waiter:
raise HTTPException(status_code=404, detail="Waiter not found")
db.delete(waiter)
db.commit()
@router.post("/{waiter_id}/assign-assistant", response_model=AssistantAssignmentOut)
def assign_assistant(waiter_id: int, assistant_id: int, db: Session = Depends(get_db), user: User = Depends(require_manager)):
existing = db.query(AssistantAssignment).filter(
AssistantAssignment.primary_waiter_id == waiter_id,
AssistantAssignment.assistant_waiter_id == assistant_id,
).first()
if existing:
raise HTTPException(status_code=400, detail="Assignment already exists")
assignment = AssistantAssignment(primary_waiter_id=waiter_id, assistant_waiter_id=assistant_id)
db.add(assignment)
db.commit()
db.refresh(assignment)
return assignment
@router.delete("/{waiter_id}/assistant", status_code=status.HTTP_204_NO_CONTENT)
def remove_assistant(waiter_id: int, db: Session = Depends(get_db), user: User = Depends(require_manager)):
assignment = db.query(AssistantAssignment).filter(
AssistantAssignment.primary_waiter_id == waiter_id
).first()
if not assignment:
raise HTTPException(status_code=404, detail="Assignment not found")
db.delete(assignment)
db.commit()