from typing import Any, List from fastapi import APIRouter, Depends, HTTPException, status 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 read_user_orders( db: Session = Depends(deps.get_db), skip: int = 0, limit: int = 100, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Retrieve current user's orders. """ orders = crud.order.get_orders_by_user( db, user_id=current_user.id, 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. """ # Validate order items if not order_in.items or len(order_in.items) == 0: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Order must contain at least one item", ) # Check if products exist and are in stock for item in order_in.items: product = crud.product.get(db, id=item.product_id) if not product or not product.is_active: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Product with id {item.product_id} not found or inactive", ) if product.stock < item.quantity: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Not enough stock for product {product.name}. Available: {product.stock}", ) # Create order order = crud.order.create_with_items( db, obj_in=order_in, user_id=current_user.id ) # Update product stock for item in order.items: product = crud.product.get(db, id=item.product_id) product.stock -= item.quantity db.add(product) # Clear user's cart cart = crud.cart.get_by_user_id(db, user_id=current_user.id) if cart: crud.cart_item.clear_cart(db, cart_id=cart.id) db.commit() return order @router.get("/{order_id}", response_model=schemas.Order) def read_order( *, db: Session = Depends(deps.get_db), order_id: int, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Get order by ID. """ order = crud.order.get_order_with_items(db, order_id=order_id) if not order: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Order not found", ) # Check if user is authorized to access this order if order.user_id != current_user.id and not current_user.is_admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not enough permissions", ) return order @router.put("/{order_id}", response_model=schemas.Order) def update_order_status( *, db: Session = Depends(deps.get_db), order_id: int, order_in: schemas.OrderUpdate, current_user: models.User = Depends(deps.get_current_admin_user), ) -> Any: """ Update order status (admin only). """ order = crud.order.get(db, id=order_id) if not order: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Order not found", ) order = crud.order.update(db, db_obj=order, obj_in=order_in) return order @router.delete("/{order_id}", status_code=status.HTTP_204_NO_CONTENT, response_model=None) def cancel_order( *, db: Session = Depends(deps.get_db), order_id: int, current_user: models.User = Depends(deps.get_current_active_user), ) -> None: """ Cancel an order. Only allowed for pending orders. """ order = crud.order.get_order_with_items(db, order_id=order_id) if not order: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Order not found", ) # Check if user is authorized to cancel this order if order.user_id != current_user.id and not current_user.is_admin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not enough permissions", ) # Check if order can be cancelled if order.status != models.OrderStatus.PENDING: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Only pending orders can be cancelled", ) # Update order status to cancelled order.status = models.OrderStatus.CANCELLED # Restore product stock for item in order.items: product = crud.product.get(db, id=item.product_id) if product: product.stock += item.quantity db.add(product) db.add(order) db.commit()