Files
Consultoría AS 049d2133f9 Implementación inicial del sistema de automatización de redes sociales
- Estructura completa del proyecto con FastAPI
- Modelos de base de datos (productos, servicios, posts, calendario, interacciones)
- Publishers para X, Threads, Instagram, Facebook
- Generador de contenido con DeepSeek API
- Worker de Celery con tareas programadas
- Dashboard básico con templates HTML
- Docker Compose para despliegue
- Documentación completa

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 01:11:44 +00:00

181 lines
5.6 KiB
Python

"""
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
}