import logging from datetime import datetime, timezone from fastapi import HTTPException, status from sqlalchemy import select, update from sqlalchemy.ext.asyncio import AsyncSession from app.models.invoice_header import InvoiceHeader from app.schemas.invoice import InvoiceHeaderCreate, InvoiceHeaderUpdate from app.utils.id import generate_id logger = logging.getLogger("videogen") async def create_header(db: AsyncSession, user_id: str, data: InvoiceHeaderCreate) -> InvoiceHeader: """创建发票抬头。""" now = datetime.now(timezone.utc) header = InvoiceHeader( id=generate_id(), user_id=user_id, type=data.type, name=data.name, tax_no=data.tax_no, register_address=data.register_address, register_phone=data.register_phone, bank_name=data.bank_name, bank_account=data.bank_account, email=data.email, is_default=data.is_default, created_at=now, updated_at=now, ) # 如果设为默认,先将其他抬头取消默认 if data.is_default: await db.execute( update(InvoiceHeader) .where(InvoiceHeader.user_id == user_id) .values(is_default=False, updated_at=now) ) db.add(header) await db.flush() return header async def get_user_headers(db: AsyncSession, user_id: str) -> list[InvoiceHeader]: """获取用户的所有发票抬头。""" result = await db.execute( select(InvoiceHeader) .where(InvoiceHeader.user_id == user_id) .order_by(InvoiceHeader.is_default.desc(), InvoiceHeader.created_at.desc()) ) return list(result.scalars().all()) async def get_header_by_id(db: AsyncSession, header_id: str, user_id: str) -> InvoiceHeader | None: """获取指定发票抬头(仅限本人)。""" result = await db.execute( select(InvoiceHeader).where( InvoiceHeader.id == header_id, InvoiceHeader.user_id == user_id, ) ) return result.scalar_one_or_none() async def update_header( db: AsyncSession, header_id: str, user_id: str, data: InvoiceHeaderUpdate ) -> InvoiceHeader: """更新发票抬头。""" header = await get_header_by_id(db, header_id, user_id) if not header: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="发票抬头不存在") update_data = {} for field, value in data.model_dump(exclude_unset=True).items(): update_data[field] = value if update_data: update_data["updated_at"] = datetime.now(timezone.utc) await db.execute( update(InvoiceHeader) .where(InvoiceHeader.id == header_id) .values(**update_data) ) # 如果设为默认,先将其他抬头取消默认 if data.is_default: now = datetime.now(timezone.utc) await db.execute( update(InvoiceHeader) .where(InvoiceHeader.user_id == user_id, InvoiceHeader.id != header_id) .values(is_default=False, updated_at=now) ) await db.refresh(header) return header async def delete_header(db: AsyncSession, header_id: str, user_id: str) -> None: """删除发票抬头。""" header = await get_header_by_id(db, header_id, user_id) if not header: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="发票抬头不存在") await db.delete(header) await db.flush() async def set_default_header(db: AsyncSession, header_id: str, user_id: str) -> InvoiceHeader: """设置默认发票抬头。""" header = await get_header_by_id(db, header_id, user_id) if not header: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="发票抬头不存在") now = datetime.now(timezone.utc) # 先取消其他默认 await db.execute( update(InvoiceHeader) .where(InvoiceHeader.user_id == user_id, InvoiceHeader.id != header_id) .values(is_default=False, updated_at=now) ) # 设置当前为默认 header.is_default = True header.updated_at = now await db.flush() return header