import logging from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.dependencies import get_db, get_current_user from app.models.invoice import Invoice, InvoiceOrder from app.models.user import User from app.schemas.invoice import InvoiceCreateRequest, InvoiceOut, InvoiceOrderOut from app.services.invoice import ( create_invoice, get_user_invoices, get_invoice_by_id, get_invoice_with_orders, ) logger = logging.getLogger("videogen") router = APIRouter(prefix="/invoices", tags=["invoices"]) @router.post("", response_model=InvoiceOut) async def create_invoice_endpoint( req: InvoiceCreateRequest, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """创建发票申请。""" invoice = await create_invoice(db, current_user.id, req) await db.commit() # 重新查询以获取关联订单 detail = await get_invoice_with_orders(db, invoice.id) return _invoice_to_out(detail["invoice"], detail["orders"]) @router.get("") async def list_invoices( page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100), current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """获取当前用户的发票列表(分页)。""" invoices, total = await get_user_invoices(db, current_user.id, page, page_size) # 加载每个发票的关联订单 items = [] for inv in invoices: result = await db.execute( select(InvoiceOrder).where(InvoiceOrder.invoice_id == inv.id) ) orders = result.scalars().all() items.append(_invoice_to_out(inv, list(orders))) return {"items": items, "total": total, "page": page, "page_size": page_size} @router.get("/{invoice_id}") async def get_invoice( invoice_id: str, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """获取发票详情(含关联订单)。""" detail = await get_invoice_with_orders(db, invoice_id) if not detail: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="发票不存在") invoice = detail["invoice"] if invoice.user_id != current_user.id: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="无权查看该发票") return _invoice_to_out(invoice, detail["orders"]) def _invoice_to_out(invoice: Invoice, orders: list[InvoiceOrder]) -> dict: """将 Invoice ORM 对象转换为响应 dict。""" return { "id": invoice.id, "user_id": invoice.user_id, "invoice_no": invoice.invoice_no, "header_type": invoice.header_type, "header_name": invoice.header_name, "header_tax_no": invoice.header_tax_no, "header_register_address": invoice.header_register_address, "header_register_phone": invoice.header_register_phone, "header_bank_name": invoice.header_bank_name, "header_bank_account": invoice.header_bank_account, "email": invoice.email, "total_amount": round(float(invoice.total_amount), 2), "total_credits": round(float(invoice.total_credits), 2), "status": invoice.status, "failure_reason": invoice.failure_reason, "issued_at": invoice.issued_at.isoformat() if invoice.issued_at else None, "created_at": invoice.created_at.isoformat() if invoice.created_at else None, "updated_at": invoice.updated_at.isoformat() if invoice.updated_at else None, "orders": [ { "id": o.id, "invoice_id": o.invoice_id, "order_id": o.order_id, "order_no": o.order_no, "amount": round(float(o.amount), 2), "credits": round(float(o.credits), 2), } for o in orders ], }