from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from typing import List from app.database import get_db from app.models import Cliente, SubCliente, MovimientoTimbre, Usuario from app.models.enums import TipoMovimiento, EstadoCliente from app.schemas import ( MovimientoCreate, MovimientoResponse, ConsumoTimbreCreate, MessageResponse ) from app.dependencies import get_current_user router = APIRouter() @router.post("/consumir/{cliente_id}", response_model=MessageResponse) def consumir_timbre_cliente( cliente_id: int, consumo: ConsumoTimbreCreate, db: Session = Depends(get_db), current_user: Usuario = Depends(get_current_user) ): """ Consumir timbres directamente del cliente (sin subcliente) """ cliente = db.query(Cliente).filter(Cliente.id == cliente_id).first() if not cliente: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Cliente no encontrado" ) # Verificar que el cliente esté activo if cliente.estado != EstadoCliente.ACTIVO: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"El cliente está {cliente.estado}" ) # Obtener timbres disponibles calculados timbres_disponibles = cliente.get_timbres_disponibles(db) # Verificar que hay timbres disponibles if timbres_disponibles < consumo.cantidad: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Timbres insuficientes. Disponibles: {timbres_disponibles}, Solicitados: {consumo.cantidad}" ) # Realizar el consumo cliente.timbres_consumidos += consumo.cantidad # Calcular nuevo balance nuevo_balance = cliente.get_timbres_disponibles(db) # Registrar movimiento movimiento = MovimientoTimbre( cliente_id=cliente.id, tipo=TipoMovimiento.CONSUMO, cantidad=consumo.cantidad, descripcion=consumo.descripcion, referencia_externa=consumo.referencia_externa, balance_cliente=nuevo_balance ) db.add(movimiento) db.commit() return { "message": f"Se consumieron {consumo.cantidad} timbre(s) exitosamente", "detail": { "cliente": cliente.nombre, "timbres_disponibles": nuevo_balance, "timbres_consumidos": cliente.timbres_consumidos } } @router.get("/historial/{cliente_id}", response_model=List[MovimientoResponse]) def obtener_historial_cliente( cliente_id: int, skip: int = 0, limit: int = 100, tipo: TipoMovimiento = None, db: Session = Depends(get_db), current_user: Usuario = Depends(get_current_user) ): """ Obtener el historial de movimientos de un cliente """ cliente = db.query(Cliente).filter(Cliente.id == cliente_id).first() if not cliente: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Cliente no encontrado" ) query = db.query(MovimientoTimbre).filter(MovimientoTimbre.cliente_id == cliente_id) if tipo: query = query.filter(MovimientoTimbre.tipo == tipo) movimientos = query.order_by(MovimientoTimbre.created_at.desc()).offset(skip).limit(limit).all() return movimientos @router.get("/historial/subcliente/{subcliente_id}", response_model=List[MovimientoResponse]) def obtener_historial_subcliente( subcliente_id: int, skip: int = 0, limit: int = 100, db: Session = Depends(get_db), current_user: Usuario = Depends(get_current_user) ): """ Obtener el historial de movimientos de un subcliente """ subcliente = db.query(SubCliente).filter(SubCliente.id == subcliente_id).first() if not subcliente: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="SubCliente no encontrado" ) movimientos = db.query(MovimientoTimbre).filter( MovimientoTimbre.subcliente_id == subcliente_id ).order_by(MovimientoTimbre.created_at.desc()).offset(skip).limit(limit).all() return movimientos @router.get("/{movimiento_id}", response_model=MovimientoResponse) def obtener_movimiento( movimiento_id: int, db: Session = Depends(get_db), current_user: Usuario = Depends(get_current_user) ): """ Obtener un movimiento específico por ID """ movimiento = db.query(MovimientoTimbre).filter(MovimientoTimbre.id == movimiento_id).first() if not movimiento: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Movimiento no encontrado" ) return movimiento @router.get("/referencia/{referencia}", response_model=MovimientoResponse) def obtener_movimiento_por_referencia( referencia: str, db: Session = Depends(get_db), current_user: Usuario = Depends(get_current_user) ): """ Obtener un movimiento por su referencia externa """ movimiento = db.query(MovimientoTimbre).filter( MovimientoTimbre.referencia_externa == referencia ).first() if not movimiento: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Movimiento no encontrado" ) return movimiento