import os from typing import Any, List, Optional from fastapi import APIRouter, Depends, HTTPException, status from fastapi.responses import FileResponse from sqlalchemy.orm import Session from app.core.auth import get_current_active_user from app.crud import invoice as crud_invoice from app.db.session import get_db from app.models.invoice import InvoiceStatus from app.models.user import User from app.schemas.invoice import Invoice, InvoiceCreate, InvoiceUpdate from app.services.invoice_generator import InvoiceGenerator router = APIRouter() @router.get("", response_model=List[Invoice]) def read_invoices( db: Session = Depends(get_db), skip: int = 0, limit: int = 100, status: Optional[InvoiceStatus] = None, current_user: User = Depends(get_current_active_user) ) -> Any: """ Retrieve invoices for the current user. """ invoices = crud_invoice.get_invoices( db, user_id=current_user.id, skip=skip, limit=limit, status=status ) return invoices @router.post("", response_model=Invoice, status_code=status.HTTP_201_CREATED) def create_invoice( *, db: Session = Depends(get_db), invoice_in: InvoiceCreate, current_user: User = Depends(get_current_active_user) ) -> Any: """ Create new invoice for the current user. """ invoice = crud_invoice.create_invoice( db, user_id=current_user.id, invoice_in=invoice_in ) return invoice @router.get("/{invoice_id}", response_model=Invoice) def read_invoice( *, db: Session = Depends(get_db), invoice_id: int, current_user: User = Depends(get_current_active_user) ) -> Any: """ Get invoice by ID. """ invoice = crud_invoice.get_invoice( db, user_id=current_user.id, invoice_id=invoice_id ) if not invoice: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Invoice not found", ) return invoice @router.patch("/{invoice_id}", response_model=Invoice) def update_invoice( *, db: Session = Depends(get_db), invoice_id: int, invoice_in: InvoiceUpdate, current_user: User = Depends(get_current_active_user) ) -> Any: """ Update an invoice. """ invoice = crud_invoice.get_invoice( db, user_id=current_user.id, invoice_id=invoice_id ) if not invoice: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Invoice not found", ) invoice = crud_invoice.update_invoice( db, user_id=current_user.id, db_invoice=invoice, invoice_in=invoice_in ) return invoice @router.delete("/{invoice_id}", response_model=Invoice) def delete_invoice( *, db: Session = Depends(get_db), invoice_id: int, current_user: User = Depends(get_current_active_user) ) -> Any: """ Delete an invoice. """ invoice = crud_invoice.get_invoice( db, user_id=current_user.id, invoice_id=invoice_id ) if not invoice: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Invoice not found", ) invoice = crud_invoice.delete_invoice( db, user_id=current_user.id, invoice_id=invoice_id ) return invoice @router.patch("/{invoice_id}/status", response_model=Invoice) def update_invoice_status( *, db: Session = Depends(get_db), invoice_id: int, status: InvoiceStatus, current_user: User = Depends(get_current_active_user) ) -> Any: """ Update an invoice status. """ invoice = crud_invoice.get_invoice( db, user_id=current_user.id, invoice_id=invoice_id ) if not invoice: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Invoice not found", ) invoice = crud_invoice.update_invoice_status( db, user_id=current_user.id, invoice_id=invoice_id, status=status ) return invoice @router.get("/{invoice_id}/pdf") def generate_invoice_pdf( *, db: Session = Depends(get_db), invoice_id: int, current_user: User = Depends(get_current_active_user) ) -> Any: """ Generate a PDF for an invoice. """ invoice = crud_invoice.get_invoice( db, user_id=current_user.id, invoice_id=invoice_id ) if not invoice: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Invoice not found", ) # Generate PDF generator = InvoiceGenerator() pdf_path = generator.generate_invoice_pdf(invoice) if not pdf_path or not os.path.exists(pdf_path): raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to generate invoice PDF", ) # Return the PDF as a file return FileResponse( pdf_path, media_type="application/pdf", filename=f"invoice_{invoice.invoice_number}.pdf" )