from fastapi import APIRouter, Depends, HTTPException, Query from prisma import Prisma from typing import List, Optional from datetime import datetime, timedelta from app.models.pedido_cliente import ( PedidoClienteCreate, PedidoClienteUpdate, PedidoClienteResponse, ReferenciaPedidoClienteUpdate ) from app.api.dependencies import get_prisma router = APIRouter(prefix="/pedidos-cliente", tags=["pedidos-cliente"]) def calcular_estado_referencia(unidades_solicitadas: int, unidades_en_stock: int) -> str: """Calcula el estado de una referencia""" unidades_pendientes = max(0, unidades_solicitadas - unidades_en_stock) if unidades_pendientes <= 0: return "completo" elif unidades_pendientes < unidades_solicitadas: return "parcial" return "pendiente" def es_urgente(fecha_cita: Optional[datetime]) -> bool: """Verifica si un pedido es urgente (menos de 12 horas)""" if not fecha_cita: return False ahora = datetime.now(fecha_cita.tzinfo) if fecha_cita.tzinfo else datetime.now() tiempo_restante = fecha_cita - ahora return 0 < tiempo_restante.total_seconds() < 12 * 3600 @router.get("/", response_model=List[PedidoClienteResponse]) async def listar_pedidos( skip: int = 0, limit: int = 100, estado: Optional[str] = None, urgente: Optional[bool] = None, matricula: Optional[str] = None, db: Prisma = Depends(get_prisma) ): """Listar pedidos de cliente""" where = {} if estado: where["estado"] = estado if matricula: where["cliente"] = {"matriculaVehiculo": {"contains": matricula, "mode": "insensitive"}} pedidos = await db.pedidocliente.find_many( where=where, skip=skip, take=limit, include={ "cliente": True, "referencias": True }, order_by={"fechaPedido": "desc"} ) # Filtrar por urgente si se solicita if urgente is not None: pedidos = [p for p in pedidos if es_urgente(p.fechaCita) == urgente] # Agregar es_urgente a cada pedido result = [] for pedido in pedidos: pedido_dict = pedido.dict() pedido_dict["es_urgente"] = es_urgente(pedido.fechaCita) result.append(pedido_dict) return result @router.get("/{pedido_id}", response_model=PedidoClienteResponse) async def obtener_pedido( pedido_id: int, db: Prisma = Depends(get_prisma) ): """Obtener un pedido por ID""" pedido = await db.pedidocliente.find_unique( where={"id": pedido_id}, include={"cliente": True, "referencias": True} ) if not pedido: raise HTTPException(status_code=404, detail="Pedido no encontrado") pedido_dict = pedido.dict() pedido_dict["es_urgente"] = es_urgente(pedido.fechaCita) return pedido_dict @router.post("/", response_model=PedidoClienteResponse, status_code=201) async def crear_pedido( pedido: PedidoClienteCreate, db: Prisma = Depends(get_prisma) ): """Crear un nuevo pedido de cliente""" try: # Verificar que el cliente existe cliente = await db.cliente.find_unique(where={"id": pedido.cliente_id}) if not cliente: raise HTTPException(status_code=404, detail="Cliente no encontrado") # Crear pedido referencias_data = pedido.referencias or [] pedido_data = pedido.dict(exclude={"referencias"}) # Convertir snake_case a camelCase para Prisma pedido_data_prisma = { "numeroPedido": pedido_data["numero_pedido"], "clienteId": pedido_data["cliente_id"], "fechaCita": pedido_data.get("fecha_cita"), "estado": pedido_data["estado"], "presupuestoId": pedido_data.get("presupuesto_id"), "archivoPdfPath": pedido_data.get("archivo_pdf_path"), "referencias": { "create": [ { "referencia": ref.referencia, "denominacion": ref.denominacion, "unidadesSolicitadas": ref.unidades_solicitadas, "unidadesEnStock": ref.unidades_en_stock, "unidadesPendientes": max(0, ref.unidades_solicitadas - ref.unidades_en_stock), "estado": calcular_estado_referencia(ref.unidades_solicitadas, ref.unidades_en_stock) } for ref in referencias_data ] } } nuevo_pedido = await db.pedidocliente.create( data=pedido_data_prisma, include={"cliente": True, "referencias": True} ) nuevo_pedido_dict = nuevo_pedido.dict() nuevo_pedido_dict["es_urgente"] = es_urgente(nuevo_pedido.fechaCita) return nuevo_pedido_dict except Exception as e: raise HTTPException(status_code=400, detail=str(e)) @router.put("/{pedido_id}", response_model=PedidoClienteResponse) async def actualizar_pedido( pedido_id: int, pedido: PedidoClienteUpdate, db: Prisma = Depends(get_prisma) ): """Actualizar un pedido""" pedido_existente = await db.pedidocliente.find_unique(where={"id": pedido_id}) if not pedido_existente: raise HTTPException(status_code=404, detail="Pedido no encontrado") data = {k: v for k, v in pedido.dict().items() if v is not None} # Convertir snake_case a camelCase data_prisma = {} field_mapping = { "numero_pedido": "numeroPedido", "cliente_id": "clienteId", "fecha_cita": "fechaCita", "presupuesto_id": "presupuestoId", "archivo_pdf_path": "archivoPdfPath" } for key, value in data.items(): prisma_key = field_mapping.get(key, key) data_prisma[prisma_key] = value pedido_actualizado = await db.pedidocliente.update( where={"id": pedido_id}, data=data_prisma, include={"cliente": True, "referencias": True} ) pedido_dict = pedido_actualizado.dict() pedido_dict["es_urgente"] = es_urgente(pedido_actualizado.fechaCita) return pedido_dict @router.post("/{pedido_id}/actualizar-estado") async def actualizar_estado_pedido( pedido_id: int, estado: str, db: Prisma = Depends(get_prisma) ): """Actualizar el estado de un pedido""" estados_validos = ["pendiente_revision", "en_revision", "pendiente_materiales", "completado"] if estado not in estados_validos: raise HTTPException(status_code=400, detail="Estado inválido") pedido = await db.pedidocliente.find_unique(where={"id": pedido_id}) if not pedido: raise HTTPException(status_code=404, detail="Pedido no encontrado") await db.pedidocliente.update( where={"id": pedido_id}, data={"estado": estado} ) return {"status": "Estado actualizado"} @router.post("/referencias/{referencia_id}/marcar-stock") async def marcar_stock_referencia( referencia_id: int, unidades_en_stock: int, db: Prisma = Depends(get_prisma) ): """Marcar unidades en stock para una referencia""" referencia = await db.referenciapedidocliente.find_unique( where={"id": referencia_id}, include={"pedidoCliente": True} ) if not referencia: raise HTTPException(status_code=404, detail="Referencia no encontrada") unidades_en_stock = max(0, unidades_en_stock) unidades_pendientes = max(0, referencia.unidadesSolicitadas - unidades_en_stock) estado = calcular_estado_referencia(referencia.unidadesSolicitadas, unidades_en_stock) referencia_actualizada = await db.referenciapedidocliente.update( where={"id": referencia_id}, data={ "unidadesEnStock": unidades_en_stock, "unidadesPendientes": unidades_pendientes, "estado": estado } ) # Verificar si todas las referencias están completas todas_referencias = await db.referenciapedidocliente.find_many( where={"pedidoClienteId": referencia.pedidoClienteId} ) todas_completas = all(ref.unidadesPendientes == 0 for ref in todas_referencias) if todas_completas and referencia.pedidoCliente.estado != "completado": await db.pedidocliente.update( where={"id": referencia.pedidoClienteId}, data={"estado": "completado"} ) elif referencia.pedidoCliente.estado == "pendiente_revision": await db.pedidocliente.update( where={"id": referencia.pedidoClienteId}, data={"estado": "en_revision"} ) return referencia_actualizada