Files
shop/backend/apps/cart/__init__.py
Marek Lenczewski e3e88cc58e wahnsinn vibe
2026-04-16 19:42:06 +02:00

141 lines
3.7 KiB
Python

import json
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy.orm import Session
from core.db import get_db
from core.redis_client import redis_client
from core.security import get_current_user_id
from .models import Cart, CartItem
router = APIRouter()
class AddItemIn(BaseModel):
product_id: int
qty: int = 1
class UpdateItemIn(BaseModel):
qty: int
class CartItemOut(BaseModel):
product_id: int
qty: int
name: dict = {}
price: float = 0.0
image_url: str = ""
line_total: float = 0.0
class CartOut(BaseModel):
items: list[CartItemOut]
subtotal: float
def _get_or_create_cart(db: Session, user_id: int) -> Cart:
cart = db.query(Cart).filter_by(user_id=user_id).first()
if not cart:
cart = Cart(user_id=user_id)
db.add(cart)
db.commit()
db.refresh(cart)
return cart
def _cart_to_out(cart: Cart) -> CartOut:
items: list[CartItemOut] = []
subtotal = 0.0
for it in cart.items:
raw = redis_client.get(f"product:{it.product_id}")
if not raw:
continue
p = json.loads(raw)
line = round(float(p["price"]) * it.qty, 2)
subtotal += line
items.append(
CartItemOut(
product_id=it.product_id,
qty=it.qty,
name=p.get("name", {}),
price=float(p["price"]),
image_url=p.get("image_url", ""),
line_total=line,
)
)
return CartOut(items=items, subtotal=round(subtotal, 2))
@router.get("", response_model=CartOut)
def get_cart(user_id: int = Depends(get_current_user_id), db: Session = Depends(get_db)):
return _cart_to_out(_get_or_create_cart(db, user_id))
@router.post("/items", response_model=CartOut)
def add_item(
body: AddItemIn,
user_id: int = Depends(get_current_user_id),
db: Session = Depends(get_db),
):
if body.qty < 1:
raise HTTPException(400, "qty must be >= 1")
if not redis_client.get(f"product:{body.product_id}"):
raise HTTPException(404, "Product not found or inactive")
cart = _get_or_create_cart(db, user_id)
existing = db.query(CartItem).filter_by(cart_id=cart.id, product_id=body.product_id).first()
if existing:
existing.qty += body.qty
else:
db.add(CartItem(cart_id=cart.id, product_id=body.product_id, qty=body.qty))
db.commit()
db.refresh(cart)
return _cart_to_out(cart)
@router.put("/items/{product_id}", response_model=CartOut)
def update_item(
product_id: int,
body: UpdateItemIn,
user_id: int = Depends(get_current_user_id),
db: Session = Depends(get_db),
):
cart = _get_or_create_cart(db, user_id)
item = db.query(CartItem).filter_by(cart_id=cart.id, product_id=product_id).first()
if not item:
raise HTTPException(404, "Not in cart")
if body.qty < 1:
db.delete(item)
else:
item.qty = body.qty
db.commit()
db.refresh(cart)
return _cart_to_out(cart)
@router.delete("/items/{product_id}", response_model=CartOut)
def remove_item(
product_id: int,
user_id: int = Depends(get_current_user_id),
db: Session = Depends(get_db),
):
cart = _get_or_create_cart(db, user_id)
item = db.query(CartItem).filter_by(cart_id=cart.id, product_id=product_id).first()
if item:
db.delete(item)
db.commit()
db.refresh(cart)
return _cart_to_out(cart)
@router.delete("", response_model=CartOut)
def clear_cart(user_id: int = Depends(get_current_user_id), db: Session = Depends(get_db)):
cart = _get_or_create_cart(db, user_id)
for it in list(cart.items):
db.delete(it)
db.commit()
db.refresh(cart)
return _cart_to_out(cart)