Automated Action e04059c1e3 Implement FastAPI cart and checkout system
- Created FastAPI application with SQLite database
- Implemented cart management (create, get, add items, remove items, clear)
- Added checkout functionality with payment processing simulation
- Set up database models using SQLAlchemy with Cart and CartItem tables
- Configured Alembic for database migrations
- Added comprehensive API documentation and examples
- Included health endpoint and CORS support
- Formatted code with ruff linting
2025-07-21 09:20:12 +00:00

204 lines
6.2 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List
import uuid
from app.db.session import get_db
from app.models.cart import Cart, CartItem
from app.schemas import (
CartCreate,
CartResponse,
CartItemCreate,
CartItemResponse,
CheckoutRequest,
CheckoutResponse,
)
router = APIRouter()
@router.post("/carts/", response_model=CartResponse)
def create_cart(cart: CartCreate, db: Session = Depends(get_db)):
db_cart = Cart(user_id=cart.user_id)
db.add(db_cart)
db.commit()
db.refresh(db_cart)
# Calculate total
total = sum(item.price * item.quantity for item in db_cart.items)
response = CartResponse.model_validate(db_cart)
response.total = total
return response
@router.get("/carts/{cart_id}", response_model=CartResponse)
def get_cart(cart_id: int, db: Session = Depends(get_db)):
cart = db.query(Cart).filter(Cart.id == cart_id).first()
if cart is None:
raise HTTPException(status_code=404, detail="Cart not found")
# Calculate total
total = sum(item.price * item.quantity for item in cart.items)
response = CartResponse.model_validate(cart)
response.total = total
return response
@router.get("/carts/user/{user_id}", response_model=List[CartResponse])
def get_user_carts(user_id: str, db: Session = Depends(get_db)):
carts = db.query(Cart).filter(Cart.user_id == user_id).all()
response_carts = []
for cart in carts:
total = sum(item.price * item.quantity for item in cart.items)
cart_response = CartResponse.model_validate(cart)
cart_response.total = total
response_carts.append(cart_response)
return response_carts
@router.post("/carts/{cart_id}/items/", response_model=CartItemResponse)
def add_item_to_cart(cart_id: int, item: CartItemCreate, db: Session = Depends(get_db)):
cart = db.query(Cart).filter(Cart.id == cart_id).first()
if cart is None:
raise HTTPException(status_code=404, detail="Cart not found")
if cart.status != "active":
raise HTTPException(status_code=400, detail="Cannot add items to inactive cart")
# Check if item already exists in cart
existing_item = (
db.query(CartItem)
.filter(CartItem.cart_id == cart_id, CartItem.product_id == item.product_id)
.first()
)
if existing_item:
# Update quantity if item exists
existing_item.quantity += item.quantity
db.commit()
db.refresh(existing_item)
return CartItemResponse.model_validate(existing_item)
else:
# Create new item if it doesn't exist
db_item = CartItem(
cart_id=cart_id,
product_id=item.product_id,
product_name=item.product_name,
price=item.price,
quantity=item.quantity,
)
db.add(db_item)
db.commit()
db.refresh(db_item)
return CartItemResponse.model_validate(db_item)
@router.put("/carts/{cart_id}/items/{item_id}", response_model=CartItemResponse)
def update_cart_item(
cart_id: int, item_id: int, quantity: int, db: Session = Depends(get_db)
):
cart = db.query(Cart).filter(Cart.id == cart_id).first()
if cart is None:
raise HTTPException(status_code=404, detail="Cart not found")
if cart.status != "active":
raise HTTPException(
status_code=400, detail="Cannot modify items in inactive cart"
)
item = (
db.query(CartItem)
.filter(CartItem.id == item_id, CartItem.cart_id == cart_id)
.first()
)
if item is None:
raise HTTPException(status_code=404, detail="Cart item not found")
if quantity <= 0:
db.delete(item)
db.commit()
return {"message": "Item removed from cart"}
else:
item.quantity = quantity
db.commit()
db.refresh(item)
return CartItemResponse.model_validate(item)
@router.delete("/carts/{cart_id}/items/{item_id}")
def remove_item_from_cart(cart_id: int, item_id: int, db: Session = Depends(get_db)):
cart = db.query(Cart).filter(Cart.id == cart_id).first()
if cart is None:
raise HTTPException(status_code=404, detail="Cart not found")
if cart.status != "active":
raise HTTPException(
status_code=400, detail="Cannot remove items from inactive cart"
)
item = (
db.query(CartItem)
.filter(CartItem.id == item_id, CartItem.cart_id == cart_id)
.first()
)
if item is None:
raise HTTPException(status_code=404, detail="Cart item not found")
db.delete(item)
db.commit()
return {"message": "Item removed from cart"}
@router.delete("/carts/{cart_id}")
def clear_cart(cart_id: int, db: Session = Depends(get_db)):
cart = db.query(Cart).filter(Cart.id == cart_id).first()
if cart is None:
raise HTTPException(status_code=404, detail="Cart not found")
if cart.status != "active":
raise HTTPException(status_code=400, detail="Cannot clear inactive cart")
# Delete all items in the cart
db.query(CartItem).filter(CartItem.cart_id == cart_id).delete()
db.commit()
return {"message": "Cart cleared successfully"}
@router.post("/checkout/", response_model=CheckoutResponse)
def checkout(checkout_request: CheckoutRequest, db: Session = Depends(get_db)):
cart = db.query(Cart).filter(Cart.id == checkout_request.cart_id).first()
if cart is None:
raise HTTPException(status_code=404, detail="Cart not found")
if cart.status != "active":
raise HTTPException(status_code=400, detail="Cart is not active")
if not cart.items:
raise HTTPException(status_code=400, detail="Cart is empty")
# Calculate total
total_amount = sum(item.price * item.quantity for item in cart.items)
# In a real system, you would process payment here
# For now, we'll simulate a successful payment
# Generate order ID
order_id = str(uuid.uuid4())
# Update cart status to checked_out
cart.status = "checked_out"
db.commit()
return CheckoutResponse(
success=True,
order_id=order_id,
total_amount=total_amount,
message="Checkout completed successfully",
)