from typing import Any, List from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from app.api.v1.deps import get_current_active_superuser, get_current_active_user from app.core.deps import get_db from app.crud.cart import cart_item as cart_item_crud from app.crud.order import order as order_crud, order_item as order_item_crud from app.crud.product import product as product_crud from app.models.order import OrderStatus from app.models.user import User from app.schemas.order import Order, OrderCreate, OrderWithItems, OrderItemCreate router = APIRouter() @router.get("/", response_model=List[Order]) def read_orders( db: Session = Depends(get_db), skip: int = 0, limit: int = 100, current_user: User = Depends(get_current_active_user), ) -> Any: """ Retrieve orders. If user is superuser, returns all orders with pagination. Otherwise, returns only the current user's orders. """ if current_user.is_superuser: orders = order_crud.get_multi(db, skip=skip, limit=limit) else: orders = order_crud.get_user_orders(db, user_id=current_user.id) return orders @router.post("/", response_model=Order) def create_order( *, db: Session = Depends(get_db), order_in: OrderCreate, current_user: User = Depends(get_current_active_user), ) -> Any: """ Create new order from user's cart. """ # Get user's cart cart_items = cart_item_crud.get_user_cart(db, user_id=current_user.id) if not cart_items: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot create order with empty cart", ) # Check stock and prepare order items order_items = [] total_amount = 0.0 for cart_item in cart_items: product = product_crud.get(db, id=cart_item.product_id) if not product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Product with ID {cart_item.product_id} not found", ) if product.stock < cart_item.quantity: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Not enough stock for product '{product.name}'. Only {product.stock} available.", ) # Create order item order_item = OrderItemCreate( product_id=cart_item.product_id, quantity=cart_item.quantity, ) order_item.unit_price = ( product.price ) # Add unit price from current product price order_items.append(order_item) # Update total amount total_amount += product.price * cart_item.quantity # Update product stock product_crud.update_stock( db, product_id=product.id, quantity=-cart_item.quantity ) # Create order order = order_crud.create_with_items( db, obj_in=order_in, user_id=current_user.id, items=order_items, total_amount=total_amount, ) # Clear cart cart_item_crud.clear_cart(db, user_id=current_user.id) return order @router.get("/{order_id}", response_model=OrderWithItems) def read_order( *, db: Session = Depends(get_db), order_id: int, current_user: User = Depends(get_current_active_user), ) -> Any: """ Get order by ID with its items. """ order = order_crud.get(db, id=order_id) if not order: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Order not found", ) # Check if user has permission to access this order if not current_user.is_superuser and order.user_id != current_user.id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not enough permissions to access this order", ) # Get order items order_items = order_item_crud.get_by_order(db, order_id=order.id) # Fetch product details for each order item items_with_products = [] for item in order_items: product = product_crud.get(db, id=item.product_id) if product: from app.schemas.order import OrderItemWithProduct item_with_product = OrderItemWithProduct.from_orm(item) item_with_product.product = product items_with_products.append(item_with_product) # Create response from app.schemas.order import OrderWithItems order_with_items = OrderWithItems.from_orm(order) order_with_items.items = items_with_products return order_with_items @router.put("/{order_id}/status", response_model=Order) def update_order_status( *, db: Session = Depends(get_db), order_id: int, status: OrderStatus, current_user: User = Depends(get_current_active_superuser), ) -> Any: """ Update order status. Only superusers can update order status. """ order = order_crud.get(db, id=order_id) if not order: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Order not found", ) order = order_crud.update_status(db, order_id=order_id, status=status) return order @router.delete( "/{order_id}", status_code=status.HTTP_204_NO_CONTENT, response_model=None ) def cancel_order( *, db: Session = Depends(get_db), order_id: int, current_user: User = Depends(get_current_active_user), ) -> Any: """ Cancel an order. Superusers can cancel any order. Regular users can only cancel their own orders and only if the order is still pending. """ order = order_crud.get(db, id=order_id) if not order: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Order not found", ) # Check permissions if not current_user.is_superuser and order.user_id != current_user.id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not enough permissions to cancel this order", ) # Regular users can only cancel pending orders if not current_user.is_superuser and order.status != OrderStatus.PENDING: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot cancel order that is not in 'pending' status", ) # Update order status to cancelled order_crud.update_status(db, order_id=order_id, status=OrderStatus.CANCELLED) # Return stock to inventory order_items = order_item_crud.get_by_order(db, order_id=order.id) for item in order_items: product_crud.update_stock( db, product_id=item.product_id, quantity=item.quantity ) return None