83 lines
2.2 KiB
Python
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
|