from datetime import UTC, datetime from fastapi import APIRouter, Depends, HTTPException from fastapi.responses import Response from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.db.models.invoice import Invoice from app.db.models.order import Order from app.db.models.order_line import OrderLine from app.db.models.tenant import Tenant from app.db.models.vehicle import Vehicle from app.db.session import get_db from app.deps import get_tenant_id from app.invoices import service from app.pdf.service import generate_factura router = APIRouter() @router.post("") async def create_invoice( data: dict, tenant_id: str = Depends(get_tenant_id), db: AsyncSession = Depends(get_db), ): order_id = data.get("order_id") if not order_id: raise HTTPException(status_code=422, detail="order_id required") try: invoice = await service.create_invoice(db, tenant_id, order_id) return {"id": invoice.id, "nr_factura": invoice.nr_factura} except ValueError as e: raise HTTPException(status_code=422, detail=str(e)) @router.get("/{invoice_id}/pdf") async def get_invoice_pdf( invoice_id: str, tenant_id: str = Depends(get_tenant_id), db: AsyncSession = Depends(get_db), ): r = await db.execute( select(Invoice).where( Invoice.id == invoice_id, Invoice.tenant_id == tenant_id ) ) invoice = r.scalar_one_or_none() if not invoice: raise HTTPException(status_code=404, detail="Invoice not found") r = await db.execute(select(Order).where(Order.id == invoice.order_id)) order = r.scalar_one() r = await db.execute(select(Vehicle).where(Vehicle.id == order.vehicle_id)) vehicle = r.scalar_one_or_none() r = await db.execute(select(Tenant).where(Tenant.id == tenant_id)) tenant = r.scalar_one() r = await db.execute( select(OrderLine).where(OrderLine.order_id == order.id) ) lines = r.scalars().all() order_data = { "id": order.id, "nr_auto": vehicle.nr_inmatriculare if vehicle else "", "client_nume": vehicle.client_nume if vehicle else "", "client_cui": vehicle.client_cui if vehicle else "", "client_adresa": vehicle.client_adresa if vehicle else "", "total_manopera": order.total_manopera, "total_materiale": order.total_materiale, "total_general": order.total_general, } invoice_data = { "nr_factura": invoice.nr_factura, "data_factura": invoice.data_factura, "total": invoice.total, } tenant_data = { "nume": tenant.nume, "cui": tenant.cui, "reg_com": tenant.reg_com, "adresa": tenant.adresa, "iban": tenant.iban, "banca": tenant.banca, } lines_data = [ { "tip": l.tip, "descriere": l.descriere, "ore": l.ore, "pret_ora": l.pret_ora, "cantitate": l.cantitate, "pret_unitar": l.pret_unitar, "um": l.um, "total": l.total, } for l in lines ] pdf_bytes = generate_factura(invoice_data, order_data, lines_data, tenant_data) return Response( content=pdf_bytes, media_type="application/pdf", headers={ "Content-Disposition": f'inline; filename="factura-{invoice.nr_factura}.pdf"' }, ) @router.delete("/{invoice_id}") async def delete_invoice( invoice_id: str, tenant_id: str = Depends(get_tenant_id), db: AsyncSession = Depends(get_db), ): r = await db.execute( select(Invoice).where( Invoice.id == invoice_id, Invoice.tenant_id == tenant_id ) ) invoice = r.scalar_one_or_none() if not invoice: raise HTTPException(status_code=404, detail="Invoice not found") order_id = invoice.order_id # Delete the invoice await db.delete(invoice) # Revert the associated order status back to VALIDAT if order_id: r = await db.execute( select(Order).where( Order.id == order_id, Order.tenant_id == tenant_id ) ) order = r.scalar_one_or_none() if order: order.status = "VALIDAT" order.updated_at = datetime.now(UTC).isoformat() await db.commit() return {"ok": True}