deep-risk/backend/app/api/v1/endpoints/tax_declaration.py
2025-12-14 20:08:27 +08:00

293 lines
10 KiB
Python

"""
税务申报表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.tax_declaration import TaxDeclaration
from app.schemas.tax import (
TaxDeclarationCreate,
TaxDeclarationUpdate,
TaxDeclarationResponse,
TaxDeclarationListResponse,
)
router = APIRouter()
@router.get("", response_model=TaxDeclarationListResponse)
async def list_tax_declarations(
page: int = Query(1, ge=1, description="页码"),
size: int = Query(10, ge=1, le=100, description="每页数量"),
vat_declaration_id: str = Query(None, description="增值税申报ID"),
taxpayer_name: str = Query(None, description="纳税人名称"),
taxpayer_id: str = Query(None, description="纳税人识别号"),
declaration_status: str = Query(None, description="申报状态"),
db: AsyncSession = Depends(get_async_session),
):
"""
获取税务申报表列表(分页查询)
"""
logger.info(f"获取税务申报表列表: page={page}, size={size}")
# 构建查询
query = select(TaxDeclaration)
# 添加过滤条件
conditions = []
if vat_declaration_id:
conditions.append(TaxDeclaration.vat_declaration_id.ilike(f"%{vat_declaration_id}%"))
if taxpayer_name:
conditions.append(TaxDeclaration.taxpayer_name.ilike(f"%{taxpayer_name}%"))
if taxpayer_id:
conditions.append(TaxDeclaration.taxpayer_id == taxpayer_id)
if declaration_status:
conditions.append(TaxDeclaration.declaration_status == declaration_status)
if conditions:
query = query.where(and_(*conditions))
# 获取总数
count_query = select(func.count()).select_from(TaxDeclaration)
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 tax in records:
response_records.append({
"id": tax.id,
"vat_declaration_id": tax.vat_declaration_id,
"taxpayer_name": tax.taxpayer_name,
"taxpayer_id": tax.taxpayer_id,
"tax_period": tax.tax_period,
"declaration_date": tax.declaration_date.isoformat() if tax.declaration_date else None,
"tax_authority_code": tax.tax_authority_code,
"tax_authority_name": tax.tax_authority_name,
"taxpayer_type": tax.taxpayer_type,
"tax_rate": tax.tax_rate,
"sales_revenue": tax.sales_revenue,
"sales_revenue_taxable": tax.sales_revenue_taxable,
"output_tax": tax.output_tax,
"input_tax": tax.input_tax,
"input_tax_deductible": tax.input_tax_deductible,
"tax_payable": tax.tax_payable,
"tax_to_pay": tax.tax_to_pay,
"refund_amount": tax.refund_amount,
"declaration_status": tax.declaration_status,
"is_reconciled": tax.is_reconciled,
})
return TaxDeclarationListResponse(
records=response_records,
total=total,
page=page,
size=size,
)
@router.get("/{vat_declaration_id}", response_model=TaxDeclarationResponse)
async def get_tax_declaration(vat_declaration_id: str, db: AsyncSession = Depends(get_async_session)):
"""
根据ID获取税务申报表详细信息
"""
logger.info(f"获取税务申报表详情: {vat_declaration_id}")
query = select(TaxDeclaration).where(TaxDeclaration.vat_declaration_id == vat_declaration_id)
result = await db.execute(query)
tax = result.scalar_one_or_none()
if not tax:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"税务申报表不存在: {vat_declaration_id}",
)
# 转换为响应格式
response = {
"id": tax.id,
"vat_declaration_id": tax.vat_declaration_id,
"taxpayer_name": tax.taxpayer_name,
"taxpayer_id": tax.taxpayer_id,
"tax_period": tax.tax_period,
"declaration_date": tax.declaration_date.isoformat() if tax.declaration_date else None,
"tax_authority_code": tax.tax_authority_code,
"tax_authority_name": tax.tax_authority_name,
"taxpayer_type": tax.taxpayer_type,
"tax_rate": tax.tax_rate,
"sales_revenue": tax.sales_revenue,
"sales_revenue_taxable": tax.sales_revenue_taxable,
"output_tax": tax.output_tax,
"input_tax": tax.input_tax,
"input_tax_deductible": tax.input_tax_deductible,
"tax_payable": tax.tax_payable,
"tax_to_pay": tax.tax_to_pay,
"refund_amount": tax.refund_amount,
"declaration_status": tax.declaration_status,
"is_reconciled": tax.is_reconciled,
}
return response
@router.post("", response_model=TaxDeclarationResponse, status_code=status.HTTP_201_CREATED)
async def create_tax_declaration(tax: TaxDeclarationCreate, db: AsyncSession = Depends(get_async_session)):
"""
创建新的税务申报表
"""
logger.info(f"创建税务申报表: {tax.taxpayer_name}")
# 生成申报ID
query = select(func.count()).select_from(TaxDeclaration)
result = await db.execute(query)
count = result.scalar()
vat_declaration_id = f"TAX{2024}{(count + 1):06d}"
# 创建新申报
new_tax = TaxDeclaration(
vat_declaration_id=vat_declaration_id,
taxpayer_name=tax.taxpayer_name,
taxpayer_id=tax.taxpayer_id,
tax_period=tax.tax_period,
declaration_date=tax.declaration_date,
tax_authority_code=tax.tax_authority_code,
tax_authority_name=tax.tax_authority_name,
taxpayer_type=tax.taxpayer_type,
tax_rate=tax.tax_rate,
sales_revenue=tax.sales_revenue,
sales_revenue_taxable=tax.sales_revenue_taxable,
output_tax=tax.output_tax,
input_tax=tax.input_tax,
input_tax_deductible=tax.input_tax_deductible,
tax_payable=tax.tax_payable,
tax_to_pay=tax.tax_to_pay,
refund_amount=tax.refund_amount,
declaration_status=tax.declaration_status,
is_reconciled=tax.is_reconciled,
)
db.add(new_tax)
await db.commit()
await db.refresh(new_tax)
# 转换为响应格式
response = {
"id": new_tax.id,
"vat_declaration_id": new_tax.vat_declaration_id,
"taxpayer_name": new_tax.taxpayer_name,
"taxpayer_id": new_tax.taxpayer_id,
"tax_period": new_tax.tax_period,
"declaration_date": new_tax.declaration_date.isoformat() if new_tax.declaration_date else None,
"tax_authority_code": new_tax.tax_authority_code,
"tax_authority_name": new_tax.tax_authority_name,
"taxpayer_type": new_tax.taxpayer_type,
"tax_rate": new_tax.tax_rate,
"sales_revenue": new_tax.sales_revenue,
"sales_revenue_taxable": new_tax.sales_revenue_taxable,
"output_tax": new_tax.output_tax,
"input_tax": new_tax.input_tax,
"input_tax_deductible": new_tax.input_tax_deductible,
"tax_payable": new_tax.tax_payable,
"tax_to_pay": new_tax.tax_to_pay,
"refund_amount": new_tax.refund_amount,
"declaration_status": new_tax.declaration_status,
"is_reconciled": new_tax.is_reconciled,
}
return response
@router.put("/{vat_declaration_id}", response_model=TaxDeclarationResponse)
async def update_tax_declaration(
vat_declaration_id: str,
tax_update: TaxDeclarationUpdate,
db: AsyncSession = Depends(get_async_session),
):
"""
更新税务申报表
"""
logger.info(f"更新税务申报表: {vat_declaration_id}")
query = select(TaxDeclaration).where(TaxDeclaration.vat_declaration_id == vat_declaration_id)
result = await db.execute(query)
tax = result.scalar_one_or_none()
if not tax:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"税务申报表不存在: {vat_declaration_id}",
)
# 更新字段
update_data = tax_update.model_dump(exclude_unset=True)
for key, value in update_data.items():
if hasattr(tax, key):
setattr(tax, key, value)
await db.commit()
await db.refresh(tax)
# 转换为响应格式
response = {
"id": tax.id,
"vat_declaration_id": tax.vat_declaration_id,
"taxpayer_name": tax.taxpayer_name,
"taxpayer_id": tax.taxpayer_id,
"tax_period": tax.tax_period,
"declaration_date": tax.declaration_date.isoformat() if tax.declaration_date else None,
"tax_authority_code": tax.tax_authority_code,
"tax_authority_name": tax.tax_authority_name,
"taxpayer_type": tax.taxpayer_type,
"tax_rate": tax.tax_rate,
"sales_revenue": tax.sales_revenue,
"sales_revenue_taxable": tax.sales_revenue_taxable,
"output_tax": tax.output_tax,
"input_tax": tax.input_tax,
"input_tax_deductible": tax.input_tax_deductible,
"tax_payable": tax.tax_payable,
"tax_to_pay": tax.tax_to_pay,
"refund_amount": tax.refund_amount,
"declaration_status": tax.declaration_status,
"is_reconciled": tax.is_reconciled,
}
return response
@router.delete("/{vat_declaration_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_tax_declaration(vat_declaration_id: str, db: AsyncSession = Depends(get_async_session)):
"""
删除税务申报表(软删除)
"""
logger.info(f"删除税务申报表: {vat_declaration_id}")
query = select(TaxDeclaration).where(TaxDeclaration.vat_declaration_id == vat_declaration_id)
result = await db.execute(query)
tax = result.scalar_one_or_none()
if not tax:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"税务申报表不存在: {vat_declaration_id}",
)
# 软删除 - 设置为草稿状态
tax.declaration_status = "rejected"
await db.commit()
return None