""" 订单业务逻辑服务层 """ from datetime import datetime from typing import Any, Optional from sqlalchemy.ext.asyncio import AsyncSession import pandas as pd import tempfile import os from app.core.log import get_logger from app.models.orders import Orders, OrderResultStatus from app.repositories.order_repository import OrderRepository from app.repositories.link_repository import LinkRepository from app.schemas.order import ( OrderStatsResponse, ) logger = get_logger(__name__) class OrderService: """订单业务服务""" def __init__(self, db: AsyncSession): self.db = db self.order_repo = OrderRepository(db) self.link_repo = LinkRepository(db) async def get_order_statistics(self) -> OrderStatsResponse: """获取订单统计信息""" stats = await self.order_repo.get_order_statistics() total = sum(stats.values()) return OrderStatsResponse( total=total, pending=stats.get("pending", 0), processing=stats.get("processing", 0), success=stats.get("success", 0), failed=stats.get("failure", 0), last_update=datetime.now().isoformat(), ) async def get_order_list( self, skip: int = 0, limit: int = 100, status_filter: OrderResultStatus | None = None, ) -> list[Orders]: """获取订单列表(包含所有关联数据)""" return await self.order_repo.get_orders_with_relations( skip, limit, status_filter ) async def get_order_detail(self, order_id: str) -> Orders | None: """获取订单详情(包含所有关联数据)""" return await self.order_repo.get_order_with_full_details(order_id) async def export_orders_to_excel( self, status_filter: str | None = None ) -> tuple[bytes, str]: """导出订单数据为Excel文件""" # 转换状态过滤器 status = None if status_filter: try: status = OrderResultStatus(status_filter) except ValueError: pass # 获取所有订单用于导出 orders = await self.order_repo.get_orders_with_relations(0, 10000, status) if not orders: raise ValueError("没有找到订单数据") # 准备导出数据 export_data = [] for order in orders: # 处理礼品卡信息(如果存在) card_codes = [] if hasattr(order, "gift_cards") and order.gift_cards: card_codes = [ gc.card_code for gc in order.gift_cards if hasattr(gc, "card_code") and gc.card_code ] # 处理用户信息(如果存在) user_name = "" user_email = "" user_phone = "" user_address = "" if hasattr(order, "user_data") and order.user_data: user_name = getattr(order.user_data, "full_name", "") user_email = getattr(order.user_data, "email", "") user_phone = getattr(order.user_data, "phone", "") # 构建地址 street = getattr(order.user_data, "street_address", "") city = getattr(order.user_data, "city", "") state = getattr(order.user_data, "state", "") zip_code = getattr(order.user_data, "zip_code", "") user_address = f"{street}, {city}, {state} {zip_code}".strip(", ") export_data.append( { "订单ID": order.id, "订单号": getattr(order, "order_number", "") or "", "状态": order.status.value, "礼品卡号": ", ".join(card_codes), "用户姓名": user_name, "邮箱": user_email, "电话": user_phone, "地址": user_address, "失败原因": getattr(order, "failure_reason", "") or "", "最终订单URL": getattr(order, "final_order_url", "") or "", "创建时间": order.created_at.strftime("%Y-%m-%d %H:%M:%S"), } ) # 创建Excel文件 df = pd.DataFrame(export_data) with tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp_file: excel_path = tmp_file.name with pd.ExcelWriter(excel_path, engine="openpyxl") as writer: df.to_excel(writer, sheet_name="订单数据", index=False) # 读取文件内容 with open(excel_path, "rb") as f: excel_content = f.read() # 删除临时文件 os.unlink(excel_path) # 生成文件名 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"订单数据_{timestamp}.xlsx" return excel_content, filename # 订单处理相关方法 async def get_pending_orders(self) -> list[Orders]: """获取pending状态的订单""" from sqlalchemy import select query = select(Orders).where(Orders.status == OrderResultStatus.PENDING) result = await self.db.execute(query) return list(result.scalars().all()) async def associate_link_to_order(self, order: Orders, link_id: str) -> bool: """将链接关联到订单""" try: order.links_id = link_id await self.db.commit() logger.info(f"成功关联链接 {link_id} 到订单 {order.id}") return True except Exception as e: await self.db.rollback() logger.error(f"关联链接到订单失败: {e}") return False async def update_order_status( self, order_id: str, status: OrderResultStatus ) -> bool: """更新订单状态""" try: await self.order_repo.update_by_id( order_id, status=status, updated_at=datetime.now(), ) logger.info(f"订单状态更新成功: {order_id} -> {status.value}") return True except Exception as e: logger.error(f"更新订单状态失败: {order_id}, error: {e}") return False async def create_order(self, user_data_id: str, links_id: str) -> str: """创建新订单""" try: order = await self.order_repo.create( user_data_id=user_data_id, links_id=links_id, status=OrderResultStatus.PENDING, ) logger.info(f"成功创建订单: {order.id}, 用户数据ID: {user_data_id}") return order.id except Exception as e: logger.error(f"创建订单失败: {e}") raise async def process_single_order(self, order_id: str) -> bool: """处理单个订单(关联链接并更新状态)""" try: # 获取订单 order = await self.order_repo.get_by_id(order_id) if not order: logger.error(f"订单未找到: {order_id}") return False # 检查订单状态 if order.status != OrderResultStatus.PENDING: logger.warning( f"订单状态非pending,跳过处理: {order_id}, status: {order.status.value}" ) return False if order.links_id: return False best_link = await self.get_best_link_for_order() if not best_link: logger.warning(f"没有可用链接,无法处理订单: {order_id}") return False # 关联链接 if not await self.associate_link_to_order(order, best_link.id): logger.error(f"关联链接失败,无法处理订单: {order_id}") return False except Exception as e: logger.error(f"处理订单失败: {order_id}, error: {e}") return True