""" API Routes para gestión de Productos. """ from datetime import datetime from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from pydantic import BaseModel from app.core.database import get_db from app.models.product import Product router = APIRouter() # =========================================== # SCHEMAS # =========================================== class ProductCreate(BaseModel): name: str description: Optional[str] = None short_description: Optional[str] = None category: str subcategory: Optional[str] = None brand: Optional[str] = None model: Optional[str] = None price: float price_usd: Optional[float] = None stock: int = 0 specs: Optional[dict] = None images: Optional[List[str]] = None main_image: Optional[str] = None tags: Optional[List[str]] = None highlights: Optional[List[str]] = None is_featured: bool = False class Config: from_attributes = True class ProductUpdate(BaseModel): name: Optional[str] = None description: Optional[str] = None short_description: Optional[str] = None category: Optional[str] = None subcategory: Optional[str] = None brand: Optional[str] = None model: Optional[str] = None price: Optional[float] = None price_usd: Optional[float] = None stock: Optional[int] = None is_available: Optional[bool] = None specs: Optional[dict] = None images: Optional[List[str]] = None main_image: Optional[str] = None tags: Optional[List[str]] = None highlights: Optional[List[str]] = None is_featured: Optional[bool] = None class Config: from_attributes = True # =========================================== # ENDPOINTS # =========================================== @router.get("/") async def list_products( category: Optional[str] = Query(None), brand: Optional[str] = Query(None), is_available: Optional[bool] = Query(None), is_featured: Optional[bool] = Query(None), min_price: Optional[float] = Query(None), max_price: Optional[float] = Query(None), limit: int = Query(50, le=100), offset: int = Query(0), db: Session = Depends(get_db) ): """Listar productos con filtros.""" query = db.query(Product) if category: query = query.filter(Product.category == category) if brand: query = query.filter(Product.brand == brand) if is_available is not None: query = query.filter(Product.is_available == is_available) if is_featured is not None: query = query.filter(Product.is_featured == is_featured) if min_price is not None: query = query.filter(Product.price >= min_price) if max_price is not None: query = query.filter(Product.price <= max_price) products = query.order_by(Product.created_at.desc()).offset(offset).limit(limit).all() return [p.to_dict() for p in products] @router.get("/categories") async def list_categories(db: Session = Depends(get_db)): """Listar categorías únicas de productos.""" categories = db.query(Product.category).distinct().all() return [c[0] for c in categories if c[0]] @router.get("/featured") async def list_featured_products(db: Session = Depends(get_db)): """Listar productos destacados.""" products = db.query(Product).filter( Product.is_featured == True, Product.is_available == True ).all() return [p.to_dict() for p in products] @router.get("/{product_id}") async def get_product(product_id: int, db: Session = Depends(get_db)): """Obtener un producto por ID.""" product = db.query(Product).filter(Product.id == product_id).first() if not product: raise HTTPException(status_code=404, detail="Producto no encontrado") return product.to_dict() @router.post("/") async def create_product(product_data: ProductCreate, db: Session = Depends(get_db)): """Crear un nuevo producto.""" product = Product(**product_data.dict()) db.add(product) db.commit() db.refresh(product) return product.to_dict() @router.put("/{product_id}") async def update_product(product_id: int, product_data: ProductUpdate, db: Session = Depends(get_db)): """Actualizar un producto.""" product = db.query(Product).filter(Product.id == product_id).first() if not product: raise HTTPException(status_code=404, detail="Producto no encontrado") update_data = product_data.dict(exclude_unset=True) for field, value in update_data.items(): setattr(product, field, value) product.updated_at = datetime.utcnow() db.commit() db.refresh(product) return product.to_dict() @router.delete("/{product_id}") async def delete_product(product_id: int, db: Session = Depends(get_db)): """Eliminar un producto.""" product = db.query(Product).filter(Product.id == product_id).first() if not product: raise HTTPException(status_code=404, detail="Producto no encontrado") db.delete(product) db.commit() return {"message": "Producto eliminado", "product_id": product_id} @router.post("/{product_id}/toggle-featured") async def toggle_featured(product_id: int, db: Session = Depends(get_db)): """Alternar estado de producto destacado.""" product = db.query(Product).filter(Product.id == product_id).first() if not product: raise HTTPException(status_code=404, detail="Producto no encontrado") product.is_featured = not product.is_featured db.commit() return { "message": f"Producto {'destacado' if product.is_featured else 'no destacado'}", "is_featured": product.is_featured }