from fastapi import APIRouter, Depends, HTTPException, Query, Response from sqlalchemy.ext.asyncio import AsyncSession from typing import Optional from pydantic import BaseModel from app.database import get_db from app.services.quotation import QuotationService from app.services.pdf_generator import pdf_generator from app.services import export from app.api.v1.deps import get_current_user_id from app.models.quotation import Quotation from app.models.customer import Customer from sqlalchemy import select, and_ router = APIRouter() class InquiryRequest(BaseModel): inquiry_text: str customer_id: Optional[str] = None @router.post("/generate-from-inquiry") async def generate_from_inquiry( data: InquiryRequest, user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): service = QuotationService(db) result = await service.generate_from_inquiry( user_id=user_id, inquiry_text=data.inquiry_text, customer_id=data.customer_id, ) return result @router.post("") async def create_quotation( data: dict, user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): service = QuotationService(db) try: quotation = await service.create_quotation(user_id, data) return quotation except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) @router.get("") async def list_quotations( page: int = Query(1, ge=1), size: int = Query(20, ge=1, le=100), user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): service = QuotationService(db) return await service.list_quotations(user_id, page, size) @router.get("/{quotation_id}") async def get_quotation( quotation_id: str, user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): service = QuotationService(db) quotation = await service.get_quotation(user_id, quotation_id) if not quotation: raise HTTPException(status_code=404, detail="Quotation not found") return quotation @router.patch("/{quotation_id}/status") async def update_quotation_status( quotation_id: str, data: dict, user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): service = QuotationService(db) quotation = await service.update_status(user_id, quotation_id, data.get("status", "draft")) if not quotation: raise HTTPException(status_code=404, detail="Quotation not found") return quotation @router.get("/export/csv") async def export_quotations( user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): service = QuotationService(db) result = await service.list_quotations(user_id, 1, 9999) items = result.get("items", []) csv_bytes = export.export_quotations_csv(items) return Response( content=csv_bytes, media_type="text/csv", headers={"Content-Disposition": "attachment; filename=quotations.csv"}, ) @router.get("/{quotation_id}/pdf") async def export_quotation_pdf( quotation_id: str, user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): service = QuotationService(db) quotation = await service.get_quotation(user_id, quotation_id) if not quotation: raise HTTPException(status_code=404, detail="Quotation not found") result = await db.execute( select(Customer).where(Customer.id == quotation["customer_id"]) ) customer = result.scalar_one_or_none() pdf_data = pdf_generator.generate_quotation({ "quotation_number": f"{quotation_id[:8].upper()}", "customer_name": customer.name if customer else "", "customer_company": customer.company if customer else "", "customer_country": customer.country if customer else "", "date": quotation["created_at"][:10] if quotation.get("created_at") else "", "valid_until": quotation.get("valid_until", ""), "currency": quotation.get("currency", "USD"), "items": quotation.get("items", []), "subtotal": quotation.get("subtotal", 0), "discount": quotation.get("discount", 0), "shipping": quotation.get("shipping", 0), "total": quotation.get("total", 0), "payment_terms": quotation.get("payment_terms", ""), "delivery_terms": quotation.get("delivery_terms", ""), "lead_time": quotation.get("lead_time", ""), "notes": quotation.get("notes", ""), }) if not pdf_data: raise HTTPException(status_code=501, detail="PDF generation not available (weasyprint not installed)") service = QuotationService(db) result = await db.execute( select(Quotation).where( and_(Quotation.id == quotation_id, Quotation.user_id == user_id) ) ) q = result.scalar_one_or_none() if q: pdf_url = f"/quotations/{quotation_id}/pdf" q.pdf_url = pdf_url await db.flush() return Response( content=pdf_data, media_type="application/pdf", headers={ "Content-Disposition": f'attachment; filename="quotation-{quotation_id[:8]}.pdf"', }, )