Files
kami_apple_exchage/backend/app/api/v1/orders.py
danial 5c486e34d3 docs(项目): 添加项目文档并进行代码调整
- 新增 CODEBUDDY.md、GEMINI.md、GEMINI_CN.md 等项目文档
- 更新 Dockerfile 和其他配置文件
- 优化部分代码结构,如 orders.py、tasks.py 等
- 新增 .dockerignore 文件
2025-09-12 19:38:24 +08:00

187 lines
7.2 KiB
Python

"""
订单管理API端点
"""
import traceback
from fastapi import APIRouter, Depends, HTTPException, status, Response
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_async_db
from app.core.log import get_logger
from app.models.orders import OrderResultStatus
from app.schemas.link import LinkResponse
from app.schemas.task import GiftCardInfoResponse
from app.schemas.user_data import UserInfoResponse
from app.services.order_business_service import OrderService
from app.schemas.order import (
OrderStatsResponse,
OrderDetailResponse,
)
router = APIRouter()
logger = get_logger(__name__)
@router.get("/stats", summary="获取订单统计", response_model=OrderStatsResponse)
async def get_order_stats(
db: AsyncSession = Depends(get_async_db),
) -> OrderStatsResponse:
"""获取订单统计信息"""
try:
result = await OrderService(db).get_order_statistics()
logger.info("获取订单统计成功")
return result
except Exception as e:
logger.error(f"获取订单统计失败: {traceback.format_exc()}", exc_info=True)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"获取订单统计失败: {str(e)}",
)
@router.get("/list", summary="获取订单列表")
async def get_orders(
skip: int = 0,
limit: int = 100,
status_filter: OrderResultStatus | None = None,
db: AsyncSession = Depends(get_async_db),
) -> list[OrderDetailResponse]:
"""获取订单列表"""
try:
orders = await OrderService(db).get_order_list(skip, limit, status_filter)
# Convert SQLAlchemy models to Pydantic response schemas
result = []
for order in orders:
link_response = LinkResponse(
id=order.links.id,
url=order.links.url,
amount=order.links.amount,
created_at=order.links.created_at.isoformat(),
updated_at=order.links.updated_at.isoformat(),
)
gift_cards = []
if order.gift_cards:
for gc in order.gift_cards:
gift_cards.append(GiftCardInfoResponse(
id=gc.id,
card_code=gc.card_code,
status=gc.status.value,
failure_reason=gc.failure_reason,
order_result_id=order.id,
created_at=gc.created_at.isoformat(),
updated_at=gc.updated_at.isoformat()
))
user_data = UserInfoResponse(
id=order.user_data.id,
email=order.user_data.email,
phone=order.user_data.phone,
created_at=order.user_data.created_at.isoformat(),
updated_at=order.user_data.updated_at.isoformat(),
full_name=order.user_data.full_name,
full_address=order.user_data.full_address,
first_name=order.user_data.first_name,
last_name=order.user_data.last_name,
street_address=order.user_data.street_address,
city=order.user_data.city,
state=order.user_data.state,
zip_code=order.user_data.zip_code
)
# Handle gift_cards being None by converting to empty list
gift_cards = order.gift_cards if order.gift_cards is not None else []
order_detail = OrderDetailResponse(
id=order.id,
status=order.status.value,
created_at=order.created_at.isoformat(),
updated_at=order.updated_at.isoformat(),
final_order_url=order.final_order_url,
failure_reason=order.failure_reason,
user_data_id=order.user_data_id,
links_id=order.links_id,
user_data=user_data,
links=link_response,
gift_cards=gift_cards
)
result.append(order_detail)
return result
except ValueError as e:
logger.warning(f"获取订单列表失败 - 参数验证错误: {str(e)}")
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
except Exception as e:
logger.error(f"获取订单列表失败: {traceback.format_exc()}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"获取订单列表失败: {str(e)}",
)
@router.get("/export", summary="导出订单数据")
async def export_orders(
status_filter: str | None = None, db: AsyncSession = Depends(get_async_db)
):
"""导出订单数据为Excel文件"""
try:
excel_content, filename = await OrderService(
db,
).export_orders_to_excel(status_filter)
logger.info(f"导出订单数据成功: filename={filename}")
return Response(
content=excel_content,
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
headers={"Content-Disposition": f"attachment; filename={filename}"},
)
except ValueError as e:
logger.warning(f"导出订单数据失败 - 参数验证错误: {str(e)}")
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
except Exception as e:
logger.error(f"导出订单数据失败: {e}", exc_info=True)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"导出订单数据失败: {str(e)}",
)
@router.get("/{order_id}", summary="获取订单详情", response_model=OrderDetailResponse)
async def get_order(order_id: str, db: AsyncSession = Depends(get_async_db)) -> OrderDetailResponse:
"""获取订单详情"""
try:
order = await OrderService(db).get_order_detail(order_id)
if not order:
logger.warning(f"获取订单详情失败 - 订单不存在: {order_id}")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="订单不存在"
)
# Convert SQLAlchemy model to Pydantic response schema
# Handle gift_cards being None by converting to empty list
gift_cards = order.gift_cards if order.gift_cards is not None else []
order_detail = OrderDetailResponse(
id=order.id,
status=order.status.value,
created_at=order.created_at.isoformat(),
updated_at=order.updated_at.isoformat(),
final_order_url=order.final_order_url,
failure_reason=order.failure_reason,
user_data_id=order.user_data_id,
links_id=order.links_id,
user_data=order.user_data,
links=order.links,
gift_cards=gift_cards
)
logger.info(f"获取订单详情成功: {order_id}")
return order_detail
except HTTPException:
raise
except Exception as e:
logger.error(f"获取订单详情失败: {e}", order_id=order_id, exc_info=True)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"获取订单详情失败: {str(e)}",
)