|
from fastapi import APIRouter, Depends, HTTPException, Request, status |
|
from sqlalchemy.orm import Session |
|
from typing import List, Dict, Any |
|
import uuid |
|
from datetime import datetime, timezone, timedelta |
|
|
|
from ..database import get_db, Dish, Order, OrderItem, Person |
|
from ..models.dish import Dish as DishModel |
|
from ..models.order import OrderCreate, Order as OrderModel |
|
from ..models.user import ( |
|
PersonCreate, |
|
PersonLogin, |
|
Person as PersonModel, |
|
PhoneAuthRequest, |
|
PhoneVerifyRequest, |
|
UsernameRequest |
|
) |
|
from ..services import firebase_auth |
|
|
|
router = APIRouter( |
|
prefix="/customer", |
|
tags=["customer"], |
|
responses={404: {"description": "Not found"}}, |
|
) |
|
|
|
|
|
|
|
@router.get("/api/menu", response_model=List[DishModel]) |
|
def get_menu(category: str = None, db: Session = Depends(get_db)): |
|
if category: |
|
dishes = db.query(Dish).filter(Dish.category == category).all() |
|
else: |
|
dishes = db.query(Dish).all() |
|
return dishes |
|
|
|
|
|
|
|
@router.get("/api/offers", response_model=List[DishModel]) |
|
def get_offers(db: Session = Depends(get_db)): |
|
dishes = db.query(Dish).filter(Dish.is_offer == 1).all() |
|
return dishes |
|
|
|
|
|
|
|
@router.get("/api/specials", response_model=List[DishModel]) |
|
def get_specials(db: Session = Depends(get_db)): |
|
dishes = db.query(Dish).filter(Dish.is_special == 1).all() |
|
return dishes |
|
|
|
|
|
|
|
@router.get("/api/categories") |
|
def get_categories(db: Session = Depends(get_db)): |
|
categories = db.query(Dish.category).distinct().all() |
|
return [category[0] for category in categories] |
|
|
|
|
|
|
|
@router.post("/api/register", response_model=PersonModel) |
|
def register_user(user: PersonCreate, db: Session = Depends(get_db)): |
|
|
|
db_user = db.query(Person).filter(Person.username == user.username).first() |
|
|
|
if db_user: |
|
|
|
db_user.visit_count += 1 |
|
db_user.last_visit = datetime.now(timezone.utc) |
|
db.commit() |
|
db.refresh(db_user) |
|
return db_user |
|
else: |
|
|
|
db_user = Person( |
|
username=user.username, |
|
password=user.password, |
|
visit_count=1, |
|
last_visit=datetime.now(timezone.utc), |
|
) |
|
db.add(db_user) |
|
db.commit() |
|
db.refresh(db_user) |
|
return db_user |
|
|
|
|
|
|
|
@router.post("/api/login", response_model=Dict[str, Any]) |
|
def login_user(user_data: PersonLogin, db: Session = Depends(get_db)): |
|
|
|
db_user = db.query(Person).filter(Person.username == user_data.username).first() |
|
|
|
if not db_user: |
|
raise HTTPException( |
|
status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid username" |
|
) |
|
|
|
|
|
if db_user.password != user_data.password: |
|
raise HTTPException( |
|
status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid password" |
|
) |
|
|
|
|
|
db_user.visit_count += 1 |
|
db_user.last_visit = datetime.now(timezone.utc) |
|
db.commit() |
|
|
|
|
|
return { |
|
"user": { |
|
"id": db_user.id, |
|
"username": db_user.username, |
|
"visit_count": db_user.visit_count, |
|
}, |
|
"message": "Login successful", |
|
} |
|
|
|
|
|
|
|
@router.post("/api/orders", response_model=OrderModel) |
|
def create_order( |
|
order: OrderCreate, person_id: int = None, db: Session = Depends(get_db) |
|
): |
|
|
|
if not person_id and hasattr(order, "username") and hasattr(order, "password"): |
|
|
|
db_user = db.query(Person).filter(Person.username == order.username).first() |
|
|
|
if db_user: |
|
|
|
db_user.visit_count += 1 |
|
db_user.last_visit = datetime.now(timezone.utc) |
|
db.commit() |
|
person_id = db_user.id |
|
else: |
|
|
|
db_user = Person( |
|
username=order.username, |
|
password=order.password, |
|
visit_count=1, |
|
last_visit=datetime.now(timezone.utc), |
|
) |
|
db.add(db_user) |
|
db.commit() |
|
db.refresh(db_user) |
|
person_id = db_user.id |
|
|
|
|
|
db_order = Order( |
|
table_number=order.table_number, |
|
unique_id=order.unique_id, |
|
person_id=person_id, |
|
status="pending", |
|
) |
|
db.add(db_order) |
|
db.commit() |
|
db.refresh(db_order) |
|
|
|
|
|
from ..database import Table |
|
|
|
db_table = db.query(Table).filter(Table.table_number == order.table_number).first() |
|
if db_table: |
|
db_table.is_occupied = True |
|
db_table.current_order_id = db_order.id |
|
db.commit() |
|
|
|
|
|
for item in order.items: |
|
|
|
dish = db.query(Dish).filter(Dish.id == item.dish_id).first() |
|
if not dish: |
|
continue |
|
|
|
db_item = OrderItem( |
|
order_id=db_order.id, |
|
dish_id=item.dish_id, |
|
quantity=item.quantity, |
|
remarks=item.remarks, |
|
) |
|
db.add(db_item) |
|
|
|
db.commit() |
|
db.refresh(db_order) |
|
|
|
return db_order |
|
|
|
|
|
|
|
@router.get("/api/orders/{order_id}", response_model=OrderModel) |
|
def get_order(order_id: int, db: Session = Depends(get_db)): |
|
|
|
order = db.query(Order).filter(Order.id == order_id).first() |
|
if order is None: |
|
raise HTTPException(status_code=404, detail="Order not found") |
|
|
|
|
|
for item in order.items: |
|
if not hasattr(item, "dish") or item.dish is None: |
|
dish = db.query(Dish).filter(Dish.id == item.dish_id).first() |
|
if dish: |
|
item.dish = dish |
|
|
|
return order |
|
|
|
|
|
|
|
@router.get("/api/person/{person_id}/orders", response_model=List[OrderModel]) |
|
def get_person_orders(person_id: int, db: Session = Depends(get_db)): |
|
|
|
orders = ( |
|
db.query(Order) |
|
.filter(Order.person_id == person_id) |
|
.order_by(Order.created_at.desc()) |
|
.all() |
|
) |
|
|
|
|
|
for order in orders: |
|
for item in order.items: |
|
if not hasattr(item, "dish") or item.dish is None: |
|
dish = db.query(Dish).filter(Dish.id == item.dish_id).first() |
|
if dish: |
|
item.dish = dish |
|
|
|
return orders |
|
|
|
|
|
|
|
@router.put("/api/orders/{order_id}/payment") |
|
def request_payment(order_id: int, db: Session = Depends(get_db)): |
|
db_order = db.query(Order).filter(Order.id == order_id).first() |
|
if db_order is None: |
|
raise HTTPException(status_code=404, detail="Order not found") |
|
|
|
|
|
db_order.status = "paid" |
|
db_order.updated_at = datetime.now(timezone.utc) |
|
|
|
|
|
from ..database import Table |
|
|
|
db_table = ( |
|
db.query(Table).filter(Table.table_number == db_order.table_number).first() |
|
) |
|
if db_table: |
|
db_table.is_occupied = False |
|
db_table.current_order_id = None |
|
db_table.updated_at = datetime.now(timezone.utc) |
|
|
|
db.commit() |
|
|
|
return {"message": "Payment completed successfully"} |
|
|
|
|
|
|
|
@router.put("/api/orders/{order_id}/cancel") |
|
def cancel_order(order_id: int, db: Session = Depends(get_db)): |
|
db_order = db.query(Order).filter(Order.id == order_id).first() |
|
if db_order is None: |
|
raise HTTPException(status_code=404, detail="Order not found") |
|
|
|
|
|
if db_order.status != "pending": |
|
raise HTTPException( |
|
status_code=400, |
|
detail="Only pending orders can be cancelled" |
|
) |
|
|
|
|
|
current_time = datetime.now(timezone.utc) |
|
order_time = db_order.created_at |
|
time_difference = current_time - order_time |
|
|
|
if time_difference > timedelta(seconds=60): |
|
raise HTTPException( |
|
status_code=400, |
|
detail="Orders can only be cancelled within 60 seconds of placing" |
|
) |
|
|
|
|
|
db_order.status = "cancelled" |
|
db_order.updated_at = current_time |
|
|
|
|
|
from ..database import Table |
|
|
|
db_table = db.query(Table).filter(Table.table_number == db_order.table_number).first() |
|
if db_table and db_table.current_order_id == db_order.id: |
|
db_table.is_occupied = False |
|
db_table.current_order_id = None |
|
db_table.updated_at = current_time |
|
|
|
db.commit() |
|
|
|
return {"message": "Order cancelled successfully"} |
|
|
|
|
|
|
|
@router.get("/api/person/{person_id}", response_model=PersonModel) |
|
def get_person(person_id: int, db: Session = Depends(get_db)): |
|
person = db.query(Person).filter(Person.id == person_id).first() |
|
if not person: |
|
raise HTTPException(status_code=404, detail="Person not found") |
|
return person |
|
|
|
|
|
|
|
@router.post("/api/phone-auth", response_model=Dict[str, Any]) |
|
def phone_auth(auth_request: PhoneAuthRequest, db: Session = Depends(get_db)): |
|
""" |
|
Initiate phone authentication by sending OTP |
|
""" |
|
try: |
|
|
|
if not auth_request.phone_number.startswith("+91"): |
|
raise HTTPException( |
|
status_code=status.HTTP_400_BAD_REQUEST, |
|
detail="Phone number must start with +91" |
|
) |
|
|
|
|
|
result = firebase_auth.verify_phone_number(auth_request.phone_number) |
|
|
|
print(f"Phone auth initiated for: {auth_request.phone_number}, table: {auth_request.table_number}") |
|
|
|
return { |
|
"success": True, |
|
"message": "Verification code sent successfully", |
|
"session_info": result.get("sessionInfo", "firebase-verification-token") |
|
} |
|
except HTTPException as e: |
|
print(f"HTTP Exception in phone_auth: {e.detail}") |
|
raise e |
|
except Exception as e: |
|
print(f"Exception in phone_auth: {str(e)}") |
|
raise HTTPException( |
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
|
detail=f"Failed to send verification code: {str(e)}" |
|
) |
|
|
|
|
|
@router.post("/api/verify-otp", response_model=Dict[str, Any]) |
|
def verify_otp(verify_request: PhoneVerifyRequest, db: Session = Depends(get_db)): |
|
""" |
|
Verify OTP and authenticate user |
|
""" |
|
try: |
|
print(f"Verifying OTP for phone: {verify_request.phone_number}") |
|
|
|
|
|
|
|
|
|
firebase_auth.verify_otp( |
|
verify_request.phone_number, |
|
verify_request.verification_code |
|
) |
|
|
|
|
|
user = db.query(Person).filter(Person.phone_number == verify_request.phone_number).first() |
|
|
|
if user: |
|
print(f"Existing user found: {user.username}") |
|
|
|
user.visit_count += 1 |
|
user.last_visit = datetime.now(timezone.utc) |
|
db.commit() |
|
db.refresh(user) |
|
|
|
return { |
|
"success": True, |
|
"message": "Authentication successful", |
|
"user_exists": True, |
|
"user_id": user.id, |
|
"username": user.username |
|
} |
|
else: |
|
print(f"New user with phone: {verify_request.phone_number}") |
|
|
|
return { |
|
"success": True, |
|
"message": "Authentication successful, but user not found", |
|
"user_exists": False |
|
} |
|
|
|
except HTTPException as e: |
|
print(f"HTTP Exception in verify_otp: {e.detail}") |
|
raise e |
|
except Exception as e: |
|
print(f"Exception in verify_otp: {str(e)}") |
|
raise HTTPException( |
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
|
detail=f"Failed to verify OTP: {str(e)}" |
|
) |
|
|
|
|
|
@router.post("/api/register-phone-user", response_model=Dict[str, Any]) |
|
def register_phone_user(user_request: UsernameRequest, db: Session = Depends(get_db)): |
|
""" |
|
Register a new user after phone authentication |
|
""" |
|
try: |
|
print(f"Registering new user with phone: {user_request.phone_number}, username: {user_request.username}") |
|
|
|
|
|
existing_user = db.query(Person).filter(Person.username == user_request.username).first() |
|
if existing_user: |
|
print(f"Username already exists: {user_request.username}") |
|
raise HTTPException( |
|
status_code=status.HTTP_400_BAD_REQUEST, |
|
detail="Username already exists" |
|
) |
|
|
|
|
|
phone_user = db.query(Person).filter(Person.phone_number == user_request.phone_number).first() |
|
if phone_user: |
|
print(f"Phone number already registered: {user_request.phone_number}") |
|
raise HTTPException( |
|
status_code=status.HTTP_400_BAD_REQUEST, |
|
detail="Phone number already registered" |
|
) |
|
|
|
|
|
new_user = Person( |
|
username=user_request.username, |
|
password="", |
|
phone_number=user_request.phone_number, |
|
visit_count=1, |
|
last_visit=datetime.now(timezone.utc) |
|
) |
|
|
|
db.add(new_user) |
|
db.commit() |
|
db.refresh(new_user) |
|
|
|
print(f"User registered successfully: {new_user.id}, {new_user.username}") |
|
|
|
return { |
|
"success": True, |
|
"message": "User registered successfully", |
|
"user_id": new_user.id, |
|
"username": new_user.username |
|
} |
|
|
|
except HTTPException as e: |
|
print(f"HTTP Exception in register_phone_user: {e.detail}") |
|
raise e |
|
except Exception as e: |
|
print(f"Exception in register_phone_user: {str(e)}") |
|
raise HTTPException( |
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, |
|
detail=f"Failed to register user: {str(e)}" |
|
) |
|
|