# app/api/v1/shop/cart.py """ Shop Shopping Cart API (Public) Public endpoints for managing shopping cart in shop frontend. Uses vendor from request.state (injected by VendorContextMiddleware). No authentication required - uses session ID for cart tracking. """ import logging from fastapi import APIRouter, Depends, Path, Body, Request, HTTPException from sqlalchemy.orm import Session from pydantic import BaseModel, Field from app.core.database import get_db from app.services.cart_service import cart_service router = APIRouter() logger = logging.getLogger(__name__) # ============================================================================ # REQUEST/RESPONSE SCHEMAS # ============================================================================ class AddToCartRequest(BaseModel): """Request model for adding to cart.""" product_id: int = Field(..., description="Product ID to add", gt=0) quantity: int = Field(1, ge=1, description="Quantity to add") class UpdateCartItemRequest(BaseModel): """Request model for updating cart item.""" quantity: int = Field(..., ge=1, description="New quantity") # ============================================================================ # CART ENDPOINTS # ============================================================================ @router.get("/cart/{session_id}") def get_cart( request: Request, session_id: str = Path(..., description="Shopping session ID"), db: Session = Depends(get_db), ): """ Get shopping cart contents for current vendor. Vendor is automatically determined from request context. No authentication required - uses session ID for cart tracking. Path Parameters: - session_id: Unique session identifier for the cart """ # Get vendor from middleware vendor = getattr(request.state, 'vendor', None) if not vendor: raise HTTPException( status_code=404, detail="Vendor not found. Please access via vendor domain/subdomain/path." ) logger.debug( f"[SHOP_API] get_cart for session {session_id}", extra={ "vendor_id": vendor.id, "vendor_code": vendor.subdomain, "session_id": session_id, } ) cart = cart_service.get_cart( db=db, vendor_id=vendor.id, session_id=session_id ) return cart @router.post("/cart/{session_id}/items") def add_to_cart( request: Request, session_id: str = Path(..., description="Shopping session ID"), cart_data: AddToCartRequest = Body(...), db: Session = Depends(get_db), ): """ Add product to cart for current vendor. Vendor is automatically determined from request context. No authentication required - uses session ID. Path Parameters: - session_id: Unique session identifier for the cart Request Body: - product_id: ID of product to add - quantity: Quantity to add (default: 1) """ # Get vendor from middleware vendor = getattr(request.state, 'vendor', None) if not vendor: raise HTTPException( status_code=404, detail="Vendor not found. Please access via vendor domain/subdomain/path." ) logger.debug( f"[SHOP_API] add_to_cart: product {cart_data.product_id}, qty {cart_data.quantity}", extra={ "vendor_id": vendor.id, "vendor_code": vendor.subdomain, "session_id": session_id, "product_id": cart_data.product_id, "quantity": cart_data.quantity, } ) result = cart_service.add_to_cart( db=db, vendor_id=vendor.id, session_id=session_id, product_id=cart_data.product_id, quantity=cart_data.quantity ) return result @router.put("/cart/{session_id}/items/{product_id}") def update_cart_item( request: Request, session_id: str = Path(..., description="Shopping session ID"), product_id: int = Path(..., description="Product ID", gt=0), cart_data: UpdateCartItemRequest = Body(...), db: Session = Depends(get_db), ): """ Update cart item quantity for current vendor. Vendor is automatically determined from request context. No authentication required - uses session ID. Path Parameters: - session_id: Unique session identifier for the cart - product_id: ID of product to update Request Body: - quantity: New quantity (must be >= 1) """ # Get vendor from middleware vendor = getattr(request.state, 'vendor', None) if not vendor: raise HTTPException( status_code=404, detail="Vendor not found. Please access via vendor domain/subdomain/path." ) logger.debug( f"[SHOP_API] update_cart_item: product {product_id}, qty {cart_data.quantity}", extra={ "vendor_id": vendor.id, "vendor_code": vendor.subdomain, "session_id": session_id, "product_id": product_id, "quantity": cart_data.quantity, } ) result = cart_service.update_cart_item( db=db, vendor_id=vendor.id, session_id=session_id, product_id=product_id, quantity=cart_data.quantity ) return result @router.delete("/cart/{session_id}/items/{product_id}") def remove_from_cart( request: Request, session_id: str = Path(..., description="Shopping session ID"), product_id: int = Path(..., description="Product ID", gt=0), db: Session = Depends(get_db), ): """ Remove item from cart for current vendor. Vendor is automatically determined from request context. No authentication required - uses session ID. Path Parameters: - session_id: Unique session identifier for the cart - product_id: ID of product to remove """ # Get vendor from middleware vendor = getattr(request.state, 'vendor', None) if not vendor: raise HTTPException( status_code=404, detail="Vendor not found. Please access via vendor domain/subdomain/path." ) logger.debug( f"[SHOP_API] remove_from_cart: product {product_id}", extra={ "vendor_id": vendor.id, "vendor_code": vendor.subdomain, "session_id": session_id, "product_id": product_id, } ) result = cart_service.remove_from_cart( db=db, vendor_id=vendor.id, session_id=session_id, product_id=product_id ) return result @router.delete("/cart/{session_id}") def clear_cart( request: Request, session_id: str = Path(..., description="Shopping session ID"), db: Session = Depends(get_db), ): """ Clear all items from cart for current vendor. Vendor is automatically determined from request context. No authentication required - uses session ID. Path Parameters: - session_id: Unique session identifier for the cart """ # Get vendor from middleware vendor = getattr(request.state, 'vendor', None) if not vendor: raise HTTPException( status_code=404, detail="Vendor not found. Please access via vendor domain/subdomain/path." ) logger.debug( f"[SHOP_API] clear_cart for session {session_id}", extra={ "vendor_id": vendor.id, "vendor_code": vendor.subdomain, "session_id": session_id, } ) result = cart_service.clear_cart( db=db, vendor_id=vendor.id, session_id=session_id ) return result