294 lines
9.2 KiB
Python
294 lines
9.2 KiB
Python
import json
|
|
import logging
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.database import get_db
|
|
from app.dependencies.auth import get_current_active_user
|
|
from app.models.cart import CartItem
|
|
from app.models.product import Product, ProductStatus
|
|
from app.models.user import User
|
|
from app.schemas.cart import (
|
|
CartItem as CartItemSchema,
|
|
)
|
|
from app.schemas.cart import (
|
|
CartItemCreate,
|
|
CartItemUpdate,
|
|
CartSummary,
|
|
)
|
|
|
|
router = APIRouter()
|
|
logger = logging.getLogger(__name__)
|
|
|
|
@router.get("/", response_model=CartSummary)
|
|
async def get_cart(
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_active_user)
|
|
):
|
|
"""
|
|
Get the current user's shopping cart.
|
|
"""
|
|
cart_items = db.query(CartItem).filter(CartItem.user_id == current_user.id).all()
|
|
|
|
# Enhance cart items with product information
|
|
items = []
|
|
total_items = 0
|
|
subtotal = 0
|
|
total_weight = 0
|
|
|
|
for item in cart_items:
|
|
# Skip items with deleted products
|
|
if not item.product:
|
|
continue
|
|
|
|
# Skip items with unavailable products
|
|
if item.product.status != ProductStatus.PUBLISHED and item.product.status != ProductStatus.OUT_OF_STOCK:
|
|
continue
|
|
|
|
# Get primary image if available
|
|
product_image = None
|
|
primary_image = next((img for img in item.product.images if img.is_primary), None)
|
|
if primary_image:
|
|
product_image = primary_image.image_url
|
|
elif item.product.images:
|
|
product_image = item.product.images[0].image_url
|
|
|
|
# Calculate current price and subtotal
|
|
current_price = item.product.current_price
|
|
item_subtotal = current_price * item.quantity
|
|
|
|
# Parse custom properties
|
|
custom_properties = None
|
|
if item.custom_properties:
|
|
try:
|
|
custom_properties = json.loads(item.custom_properties)
|
|
except:
|
|
custom_properties = None
|
|
|
|
# Create enhanced cart item
|
|
cart_item = {
|
|
"id": item.id,
|
|
"user_id": item.user_id,
|
|
"product_id": item.product_id,
|
|
"quantity": item.quantity,
|
|
"price_at_addition": item.price_at_addition,
|
|
"custom_properties": custom_properties,
|
|
"created_at": item.created_at,
|
|
"updated_at": item.updated_at,
|
|
"product_name": item.product.name,
|
|
"product_image": product_image,
|
|
"current_price": current_price,
|
|
"subtotal": item_subtotal
|
|
}
|
|
|
|
items.append(cart_item)
|
|
total_items += item.quantity
|
|
subtotal += item_subtotal
|
|
|
|
# Add weight if available
|
|
if item.product.weight:
|
|
total_weight += item.product.weight * item.quantity
|
|
|
|
return {
|
|
"items": items,
|
|
"total_items": total_items,
|
|
"subtotal": subtotal,
|
|
"total_weight": total_weight if total_weight > 0 else None
|
|
}
|
|
|
|
@router.post("/items", response_model=CartItemSchema)
|
|
async def add_cart_item(
|
|
item_in: CartItemCreate,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_active_user)
|
|
):
|
|
"""
|
|
Add an item to the shopping cart.
|
|
"""
|
|
# Check if product exists and is available
|
|
product = db.query(Product).filter(Product.id == item_in.product_id).first()
|
|
if not product:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Product not found"
|
|
)
|
|
|
|
if product.status != ProductStatus.PUBLISHED:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Product is not available for purchase"
|
|
)
|
|
|
|
if product.stock_quantity < item_in.quantity:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=f"Not enough stock available. Only {product.stock_quantity} items left."
|
|
)
|
|
|
|
# Check if the item is already in the cart
|
|
existing_item = db.query(CartItem).filter(
|
|
CartItem.user_id == current_user.id,
|
|
CartItem.product_id == item_in.product_id
|
|
).first()
|
|
|
|
if existing_item:
|
|
# Update quantity if item already exists
|
|
new_quantity = existing_item.quantity + item_in.quantity
|
|
|
|
# Check stock for the new quantity
|
|
if product.stock_quantity < new_quantity:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=f"Not enough stock available. Only {product.stock_quantity} items left."
|
|
)
|
|
|
|
existing_item.quantity = new_quantity
|
|
|
|
# Update custom properties if provided
|
|
if item_in.custom_properties:
|
|
existing_item.custom_properties = json.dumps(item_in.custom_properties)
|
|
|
|
db.commit()
|
|
db.refresh(existing_item)
|
|
cart_item = existing_item
|
|
else:
|
|
# Serialize custom properties if provided
|
|
custom_properties_json = None
|
|
if item_in.custom_properties:
|
|
custom_properties_json = json.dumps(item_in.custom_properties)
|
|
|
|
# Create new cart item
|
|
cart_item = CartItem(
|
|
user_id=current_user.id,
|
|
product_id=item_in.product_id,
|
|
quantity=item_in.quantity,
|
|
price_at_addition=product.current_price,
|
|
custom_properties=custom_properties_json
|
|
)
|
|
|
|
db.add(cart_item)
|
|
db.commit()
|
|
db.refresh(cart_item)
|
|
|
|
# Enhance cart item with product information for response
|
|
product_image = None
|
|
primary_image = next((img for img in product.images if img.is_primary), None)
|
|
if primary_image:
|
|
product_image = primary_image.image_url
|
|
elif product.images:
|
|
product_image = product.images[0].image_url
|
|
|
|
cart_item.product_name = product.name
|
|
cart_item.product_image = product_image
|
|
cart_item.current_price = product.current_price
|
|
cart_item.subtotal = product.current_price * cart_item.quantity
|
|
|
|
logger.info(f"Item added to cart: Product {product.name} (ID: {product.id}) for user {current_user.email}")
|
|
return cart_item
|
|
|
|
@router.put("/items/{item_id}", response_model=CartItemSchema)
|
|
async def update_cart_item(
|
|
item_id: str,
|
|
item_in: CartItemUpdate,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_active_user)
|
|
):
|
|
"""
|
|
Update a cart item.
|
|
"""
|
|
# Find the cart item
|
|
cart_item = db.query(CartItem).filter(
|
|
CartItem.id == item_id,
|
|
CartItem.user_id == current_user.id
|
|
).first()
|
|
|
|
if not cart_item:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Cart item not found"
|
|
)
|
|
|
|
# Check if product exists
|
|
product = db.query(Product).filter(Product.id == cart_item.product_id).first()
|
|
if not product:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Product not found"
|
|
)
|
|
|
|
# Update quantity if provided
|
|
if item_in.quantity is not None:
|
|
# Check stock
|
|
if product.stock_quantity < item_in.quantity:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=f"Not enough stock available. Only {product.stock_quantity} items left."
|
|
)
|
|
|
|
cart_item.quantity = item_in.quantity
|
|
|
|
# Update custom properties if provided
|
|
if item_in.custom_properties is not None:
|
|
cart_item.custom_properties = json.dumps(item_in.custom_properties)
|
|
|
|
db.commit()
|
|
db.refresh(cart_item)
|
|
|
|
# Enhance cart item with product information for response
|
|
product_image = None
|
|
primary_image = next((img for img in product.images if img.is_primary), None)
|
|
if primary_image:
|
|
product_image = primary_image.image_url
|
|
elif product.images:
|
|
product_image = product.images[0].image_url
|
|
|
|
cart_item.product_name = product.name
|
|
cart_item.product_image = product_image
|
|
cart_item.current_price = product.current_price
|
|
cart_item.subtotal = product.current_price * cart_item.quantity
|
|
|
|
logger.info(f"Cart item updated: ID {item_id} for user {current_user.email}")
|
|
return cart_item
|
|
|
|
@router.delete("/items/{item_id}", response_model=dict)
|
|
async def remove_cart_item(
|
|
item_id: str,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_active_user)
|
|
):
|
|
"""
|
|
Remove an item from the shopping cart.
|
|
"""
|
|
cart_item = db.query(CartItem).filter(
|
|
CartItem.id == item_id,
|
|
CartItem.user_id == current_user.id
|
|
).first()
|
|
|
|
if not cart_item:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Cart item not found"
|
|
)
|
|
|
|
# Delete the cart item
|
|
db.delete(cart_item)
|
|
db.commit()
|
|
|
|
logger.info(f"Cart item removed: ID {item_id} for user {current_user.email}")
|
|
return {"message": "Item removed from cart successfully"}
|
|
|
|
@router.delete("/", response_model=dict)
|
|
async def clear_cart(
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_active_user)
|
|
):
|
|
"""
|
|
Clear the current user's shopping cart.
|
|
"""
|
|
db.query(CartItem).filter(CartItem.user_id == current_user.id).delete()
|
|
db.commit()
|
|
|
|
logger.info(f"Cart cleared for user {current_user.email}")
|
|
return {"message": "Cart cleared successfully"}
|