""" 发票数据API路由 """ from typing import Any, List, Optional from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy import select, func, and_, or_ from sqlalchemy.ext.asyncio import AsyncSession from loguru import logger from app.database import get_async_session from app.models.invoice import Invoice from app.schemas.invoice import ( InvoiceCreate, InvoiceUpdate, InvoiceResponse, InvoiceListResponse, ) router = APIRouter() @router.get("", response_model=InvoiceListResponse) async def list_invoices( page: int = Query(1, ge=1, description="页码"), size: int = Query(10, ge=1, le=100, description="每页数量"), invoice_id: str = Query(None, description="发票ID"), invoice_type: str = Query(None, description="发票类型"), seller_name: str = Query(None, description="销售方名称"), invoice_status: str = Query(None, description="发票状态"), db: AsyncSession = Depends(get_async_session), ): """ 获取发票数据列表(分页查询) """ logger.info(f"获取发票数据列表: page={page}, size={size}") # 构建查询 query = select(Invoice) # 添加过滤条件 conditions = [] if invoice_id: conditions.append(Invoice.invoice_id.ilike(f"%{invoice_id}%")) if invoice_type: conditions.append(Invoice.invoice_type == invoice_type) if seller_name: conditions.append(Invoice.seller_name.ilike(f"%{seller_name}%")) if invoice_status: conditions.append(Invoice.invoice_status == invoice_status) if conditions: query = query.where(and_(*conditions)) # 获取总数 count_query = select(func.count()).select_from(Invoice) if conditions: count_query = count_query.where(and_(*conditions)) total_result = await db.execute(count_query) total = total_result.scalar() # 分页 query = query.offset((page - 1) * size).limit(size) # 执行查询 result = await db.execute(query) records = result.scalars().all() # 转换为响应格式 response_records = [] for invoice in records: response_records.append({ "id": invoice.id, "invoice_id": invoice.invoice_id, "invoice_code": invoice.invoice_code, "invoice_no": invoice.invoice_no, "invoice_type": invoice.invoice_type, "direction": invoice.direction, "invoice_date": invoice.invoice_date.isoformat() if invoice.invoice_date else None, "purchaser_name": invoice.purchaser_name, "purchaser_tax_no": invoice.purchaser_tax_no, "seller_name": invoice.seller_name, "seller_tax_no": invoice.seller_tax_no, "total_amount": invoice.total_amount, "total_tax": invoice.total_tax, "total_amount_with_tax": invoice.total_amount_with_tax, "amount_in_words": invoice.amount_in_words, "invoice_status": invoice.invoice_status, "is_verified": invoice.is_verified, "verified_time": invoice.verified_time.isoformat() if invoice.verified_time else None, "is_red_invoice": invoice.is_red_invoice, "red_reason": invoice.red_reason, "remark": invoice.remark, "pdf_url": invoice.pdf_url, }) return InvoiceListResponse( records=response_records, total=total, page=page, size=size, ) @router.get("/{invoice_id}", response_model=InvoiceResponse) async def get_invoice(invoice_id: str, db: AsyncSession = Depends(get_async_session)): """ 根据ID获取发票数据详细信息 """ logger.info(f"获取发票数据详情: {invoice_id}") query = select(Invoice).where(Invoice.invoice_id == invoice_id) result = await db.execute(query) invoice = result.scalar_one_or_none() if not invoice: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"发票数据不存在: {invoice_id}", ) # 转换为响应格式 response = { "id": invoice.id, "invoice_id": invoice.invoice_id, "invoice_code": invoice.invoice_code, "invoice_no": invoice.invoice_no, "invoice_type": invoice.invoice_type, "direction": invoice.direction, "invoice_date": invoice.invoice_date.isoformat() if invoice.invoice_date else None, "purchaser_name": invoice.purchaser_name, "purchaser_tax_no": invoice.purchaser_tax_no, "seller_name": invoice.seller_name, "seller_tax_no": invoice.seller_tax_no, "total_amount": invoice.total_amount, "total_tax": invoice.total_tax, "total_amount_with_tax": invoice.total_amount_with_tax, "amount_in_words": invoice.amount_in_words, "invoice_status": invoice.invoice_status, "is_verified": invoice.is_verified, "verified_time": invoice.verified_time.isoformat() if invoice.verified_time else None, "is_red_invoice": invoice.is_red_invoice, "red_reason": invoice.red_reason, "remark": invoice.remark, "pdf_url": invoice.pdf_url, } return response @router.post("", response_model=InvoiceResponse, status_code=status.HTTP_201_CREATED) async def create_invoice(invoice: InvoiceCreate, db: AsyncSession = Depends(get_async_session)): """ 创建新的发票数据 """ logger.info(f"创建发票数据: {invoice.invoice_no}") # 生成发票ID query = select(func.count()).select_from(Invoice) result = await db.execute(query) count = result.scalar() invoice_id = f"INV{2024}{(count + 1):06d}" # 创建新发票 new_invoice = Invoice( invoice_id=invoice_id, invoice_code=invoice.invoice_code, invoice_no=invoice.invoice_no, invoice_type=invoice.invoice_type, direction=invoice.direction, invoice_date=invoice.invoice_date, purchaser_name=invoice.purchaser_name, purchaser_tax_no=invoice.purchaser_tax_no, seller_name=invoice.seller_name, seller_tax_no=invoice.seller_tax_no, total_amount=invoice.total_amount, total_tax=invoice.total_tax, total_amount_with_tax=invoice.total_amount_with_tax, amount_in_words=invoice.amount_in_words, invoice_status=invoice.invoice_status, is_verified=invoice.is_verified, verified_time=invoice.verified_time, is_red_invoice=invoice.is_red_invoice, red_reason=invoice.red_reason, remark=invoice.remark, pdf_url=invoice.pdf_url, ) db.add(new_invoice) await db.commit() await db.refresh(new_invoice) # 转换为响应格式 response = { "id": new_invoice.id, "invoice_id": new_invoice.invoice_id, "invoice_code": new_invoice.invoice_code, "invoice_no": new_invoice.invoice_no, "invoice_type": new_invoice.invoice_type, "direction": new_invoice.direction, "invoice_date": new_invoice.invoice_date.isoformat() if new_invoice.invoice_date else None, "purchaser_name": new_invoice.purchaser_name, "purchaser_tax_no": new_invoice.purchaser_tax_no, "seller_name": new_invoice.seller_name, "seller_tax_no": new_invoice.seller_tax_no, "total_amount": new_invoice.total_amount, "total_tax": new_invoice.total_tax, "total_amount_with_tax": new_invoice.total_amount_with_tax, "amount_in_words": new_invoice.amount_in_words, "invoice_status": new_invoice.invoice_status, "is_verified": new_invoice.is_verified, "verified_time": new_invoice.verified_time.isoformat() if new_invoice.verified_time else None, "is_red_invoice": new_invoice.is_red_invoice, "red_reason": new_invoice.red_reason, "remark": new_invoice.remark, "pdf_url": new_invoice.pdf_url, } return response @router.put("/{invoice_id}", response_model=InvoiceResponse) async def update_invoice( invoice_id: str, invoice_update: InvoiceUpdate, db: AsyncSession = Depends(get_async_session), ): """ 更新发票数据 """ logger.info(f"更新发票数据: {invoice_id}") query = select(Invoice).where(Invoice.invoice_id == invoice_id) result = await db.execute(query) invoice = result.scalar_one_or_none() if not invoice: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"发票数据不存在: {invoice_id}", ) # 更新字段 update_data = invoice_update.model_dump(exclude_unset=True) for key, value in update_data.items(): if hasattr(invoice, key): setattr(invoice, key, value) await db.commit() await db.refresh(invoice) # 转换为响应格式 response = { "id": invoice.id, "invoice_id": invoice.invoice_id, "invoice_code": invoice.invoice_code, "invoice_no": invoice.invoice_no, "invoice_type": invoice.invoice_type, "direction": invoice.direction, "invoice_date": invoice.invoice_date.isoformat() if invoice.invoice_date else None, "purchaser_name": invoice.purchaser_name, "purchaser_tax_no": invoice.purchaser_tax_no, "seller_name": invoice.seller_name, "seller_tax_no": invoice.seller_tax_no, "total_amount": invoice.total_amount, "total_tax": invoice.total_tax, "total_amount_with_tax": invoice.total_amount_with_tax, "amount_in_words": invoice.amount_in_words, "invoice_status": invoice.invoice_status, "is_verified": invoice.is_verified, "verified_time": invoice.verified_time.isoformat() if invoice.verified_time else None, "is_red_invoice": invoice.is_red_invoice, "red_reason": invoice.red_reason, "remark": invoice.remark, "pdf_url": invoice.pdf_url, } return response @router.delete("/{invoice_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_invoice(invoice_id: str, db: AsyncSession = Depends(get_async_session)): """ 删除发票数据(软删除) """ logger.info(f"删除发票数据: {invoice_id}") query = select(Invoice).where(Invoice.invoice_id == invoice_id) result = await db.execute(query) invoice = result.scalar_one_or_none() if not invoice: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"发票数据不存在: {invoice_id}", ) # 软删除 - 设置为已作废状态 invoice.invoice_status = "cancelled" await db.commit() return None