from typing import Any, List, Optional from decimal import Decimal from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from app.api.deps import get_db, get_current_active_user, get_current_admin_user from app.crud.crud_purchase_order import purchase_order from app.crud.crud_product import product from app.models.user import User as UserModel from app.schemas.purchase_order import PurchaseOrder, PurchaseOrderCreate, PurchaseOrderUpdate router = APIRouter() @router.get("/", response_model=List[PurchaseOrder]) def read_purchase_orders( db: Session = Depends(get_db), skip: int = 0, limit: int = 100, status: Optional[str] = None, current_user: UserModel = Depends(get_current_active_user), ) -> Any: """ Retrieve purchase orders with their items. Filter by status if provided. """ orders = purchase_order.get_multi_with_items(db, skip=skip, limit=limit) # Apply status filter if status: orders = [order for order in orders if order.status == status] # Calculate total amount for each order for order in orders: order.total_amount = purchase_order.get_total_amount(db, id=order.id) return orders @router.post("/", response_model=PurchaseOrder) def create_purchase_order( *, db: Session = Depends(get_db), order_in: PurchaseOrderCreate, current_user: UserModel = Depends(get_current_active_user), ) -> Any: """ Create new purchase order with items. """ # Verify all products exist for item in order_in.items: prod = product.get(db, id=item.product_id) if not prod: raise HTTPException( status_code=404, detail=f"Product with id {item.product_id} not found" ) # Create purchase order with items new_order = purchase_order.create_with_items( db, obj_in=order_in, user_id=current_user.id ) # Calculate total amount new_order.total_amount = purchase_order.get_total_amount(db, id=new_order.id) return new_order @router.get("/{id}", response_model=PurchaseOrder) def read_purchase_order( *, db: Session = Depends(get_db), id: int, current_user: UserModel = Depends(get_current_active_user), ) -> Any: """ Get purchase order by ID with its items. """ order = purchase_order.get_with_items(db, id=id) if not order: raise HTTPException(status_code=404, detail="Purchase order not found") # Calculate total amount order.total_amount = purchase_order.get_total_amount(db, id=order.id) return order @router.put("/{id}", response_model=PurchaseOrder) def update_purchase_order( *, db: Session = Depends(get_db), id: int, order_in: PurchaseOrderUpdate, current_user: UserModel = Depends(get_current_active_user), ) -> Any: """ Update a purchase order (but not its items). Can only update pending orders. """ order = purchase_order.get(db, id=id) if not order: raise HTTPException(status_code=404, detail="Purchase order not found") # Only allow updates to pending orders if order.status != "pending": raise HTTPException( status_code=400, detail=f"Cannot update purchase order with status {order.status}. Only pending orders can be updated." ) updated_order = purchase_order.update(db, db_obj=order, obj_in=order_in) # Get full order with items for response result = purchase_order.get_with_items(db, id=updated_order.id) # Calculate total amount result.total_amount = purchase_order.get_total_amount(db, id=result.id) return result @router.post("/{id}/receive", response_model=PurchaseOrder) def receive_purchase_order( *, db: Session = Depends(get_db), id: int, current_user: UserModel = Depends(get_current_active_user), ) -> Any: """ Mark a purchase order as received and update inventory. """ order = purchase_order.get(db, id=id) if not order: raise HTTPException(status_code=404, detail="Purchase order not found") # Only allow receiving pending orders if order.status != "pending": raise HTTPException( status_code=400, detail=f"Cannot receive purchase order with status {order.status}. Only pending orders can be received." ) # Update status and inventory received_order = purchase_order.receive_order(db, id=id) # Calculate total amount received_order.total_amount = purchase_order.get_total_amount(db, id=received_order.id) return received_order @router.post("/{id}/cancel", response_model=PurchaseOrder) def cancel_purchase_order( *, db: Session = Depends(get_db), id: int, current_user: UserModel = Depends(get_current_active_user), ) -> Any: """ Cancel a purchase order. """ order = purchase_order.get(db, id=id) if not order: raise HTTPException(status_code=404, detail="Purchase order not found") # Only allow cancelling pending orders if order.status != "pending": raise HTTPException( status_code=400, detail=f"Cannot cancel purchase order with status {order.status}. Only pending orders can be cancelled." ) # Update status cancelled_order = purchase_order.cancel_order(db, id=id) # Get full order with items for response result = purchase_order.get_with_items(db, id=cancelled_order.id) # Calculate total amount result.total_amount = purchase_order.get_total_amount(db, id=result.id) return result