from typing import Any, List from fastapi import APIRouter, Depends, HTTPException, Path, Query from sqlalchemy.orm import Session from app import crud, models, schemas from app.api import deps router = APIRouter() @router.get("/", response_model=List[schemas.Order]) def list_orders( db: Session = Depends(deps.get_db), skip: int = Query(0, description="Skip first N items"), limit: int = Query(100, description="Limit the number of items returned"), customer_id: int = Query(None, description="Filter by customer ID"), current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Retrieve orders with optional customer filtering """ if customer_id: # Check permissions if not superuser if not crud.user.is_superuser(current_user): customer = crud.customer.get(db, id=customer_id) if not customer or not customer.user_id or customer.user_id != current_user.id: raise HTTPException( status_code=403, detail="Not enough permissions to access these orders" ) orders = crud.order.get_by_customer(db, customer_id=customer_id, skip=skip, limit=limit) else: # Non-superusers can only see their own orders if not crud.user.is_superuser(current_user): # Find customer associated with current user customer = db.query(models.Customer).filter(models.Customer.user_id == current_user.id).first() if not customer: return [] orders = crud.order.get_by_customer(db, customer_id=customer.id, skip=skip, limit=limit) else: orders = crud.order.get_multi(db, skip=skip, limit=limit) return orders @router.post("/", response_model=schemas.Order) def create_order( *, db: Session = Depends(deps.get_db), order_in: schemas.OrderCreate, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Create a new order """ # Verify customer exists customer = crud.customer.get(db, id=order_in.customer_id) if not customer: raise HTTPException(status_code=404, detail="Customer not found") # Check permissions if not superuser if not crud.user.is_superuser(current_user): if not customer.user_id or customer.user_id != current_user.id: raise HTTPException( status_code=403, detail="Not enough permissions to create order for this customer" ) # Verify products exist and have enough inventory for item in order_in.items: product = crud.product.get(db, id=item.product_id) if not product: raise HTTPException( status_code=404, detail=f"Product with ID {item.product_id} not found" ) # Check inventory inventory = crud.inventory.get_by_product_id(db, product_id=item.product_id) if not inventory or inventory.quantity < item.quantity: raise HTTPException( status_code=400, detail=f"Not enough inventory for product {product.name}" ) # Create the order order = crud.order.create_with_items(db, obj_in=order_in) # Update inventory for item in order.items: inventory = crud.inventory.get_by_product_id(db, product_id=item.product_id) if inventory: crud.inventory.update_quantity( db, inventory_id=inventory.id, quantity_change=-item.quantity ) return order @router.get("/{order_id}", response_model=schemas.Order) def get_order( *, db: Session = Depends(deps.get_db), order_id: int = Path(..., description="The ID of the order to get"), current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Get a specific order by id """ order = crud.order.get_with_items(db, order_id=order_id) if not order: raise HTTPException(status_code=404, detail="Order not found") # Check permissions if not superuser if not crud.user.is_superuser(current_user): customer = crud.customer.get(db, id=order.customer_id) if not customer or not customer.user_id or customer.user_id != current_user.id: raise HTTPException( status_code=403, detail="Not enough permissions to access this order" ) return order @router.put("/{order_id}", response_model=schemas.Order) def update_order( *, db: Session = Depends(deps.get_db), order_id: int = Path(..., description="The ID of the order to update"), order_in: schemas.OrderUpdate, current_user: models.User = Depends(deps.get_current_active_superuser), ) -> Any: """ Update an order's details (admin only) """ order = crud.order.get(db, id=order_id) if not order: raise HTTPException(status_code=404, detail="Order not found") order = crud.order.update(db, db_obj=order, obj_in=order_in) return order @router.delete("/{order_id}", response_model=schemas.Order) def cancel_order( *, db: Session = Depends(deps.get_db), order_id: int = Path(..., description="The ID of the order to cancel"), current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Cancel an order and restore inventory """ order = crud.order.get_with_items(db, order_id=order_id) if not order: raise HTTPException(status_code=404, detail="Order not found") # Check permissions if not superuser if not crud.user.is_superuser(current_user): customer = crud.customer.get(db, id=order.customer_id) if not customer or not customer.user_id or customer.user_id != current_user.id: raise HTTPException( status_code=403, detail="Not enough permissions to cancel this order" ) # Check if order can be canceled if order.status not in ["pending", "processing"]: raise HTTPException( status_code=400, detail=f"Cannot cancel order with status {order.status}" ) # Update order status order = crud.order.update( db, db_obj=order, obj_in={"status": "cancelled", "payment_status": "refunded"} ) # Restore inventory for item in order.items: inventory = crud.inventory.get_by_product_id(db, product_id=item.product_id) if inventory: crud.inventory.update_quantity( db, inventory_id=inventory.id, quantity_change=item.quantity ) # TODO: Handle Stripe refund if payment was made return order