173 lines
4.9 KiB
Python

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()