Files

83 lines
2.2 KiB
Python

from __future__ import annotations
from decimal import Decimal
from fastapi import Request
from sqlalchemy import func, select
from sqlalchemy.orm import Session
from app.models import Product, ProductKey
def get_cart_map(request: Request) -> dict[str, int]:
raw = request.session.get("cart") or {}
cart: dict[str, int] = {}
for key, value in raw.items():
try:
qty = int(value)
except (TypeError, ValueError):
continue
if qty > 0:
cart[str(key)] = qty
return cart
def save_cart(request: Request, cart: dict[str, int]) -> None:
request.session["cart"] = {str(k): int(v) for k, v in cart.items() if int(v) > 0}
def cart_count(request: Request) -> int:
return sum(get_cart_map(request).values())
def available_stock(db: Session, product_id: int) -> int:
return int(
db.scalar(
select(func.count())
.select_from(ProductKey)
.where(ProductKey.product_id == product_id, ProductKey.is_sold.is_(False))
)
or 0
)
def build_cart_items(db: Session, request: Request) -> tuple[list[dict], Decimal]:
cart = get_cart_map(request)
items: list[dict] = []
total = Decimal("0.00")
if not cart:
return items, total
product_ids = [int(pid) for pid in cart.keys()]
products = {
p.id: p
for p in db.scalars(select(Product).where(Product.id.in_(product_ids))).all()
}
clean_cart = dict(cart)
for pid_str, qty in cart.items():
product = products.get(int(pid_str))
if not product or not product.is_active:
clean_cart.pop(pid_str, None)
continue
stock = available_stock(db, product.id)
qty = min(qty, max(stock, 0))
if qty <= 0:
clean_cart.pop(pid_str, None)
continue
clean_cart[pid_str] = qty
line_total = product.price * qty
total += line_total
items.append(
{
"product": product,
"quantity": qty,
"stock": stock,
"line_total": line_total,
}
)
if clean_cart != cart:
save_cart(request, clean_cart)
return items, total