""" 订单数据访问层。 负责封装销售订单(SalesOrder)、订单明细(SalesOrderItem)、 供应商(Supplier)及供应商短信确认日志(OrderSupplierTextLog)的数据库查询操作。 提供订单的增删改查、状态流转、取消流程、供应商确认等功能。 被 OrderService、LogisticsService 调用。 """ from datetime import datetime from sqlalchemy import func, select from sqlalchemy.orm import Session from backend.app.models.business import OrderSupplierTextLog, SalesOrder, SalesOrderItem, Supplier class OrderRepository: """订单数据访问层,封装销售订单及其相关表的数据库操作。 被 OrderService、LogisticsService 调用。 """ def list_orders(self, session: Session) -> list[SalesOrder]: """查询所有未删除的订单列表(不做分页),按 id 降序排列。 :param session: 数据库会话 :return: 订单列表 被 OrderService 内部使用。 """ stmt = select(SalesOrder).where(SalesOrder.deleted == 0).order_by(SalesOrder.id.desc()) return list(session.execute(stmt).scalars()) def list_orders_by_filters(self, session: Session, filters: dict) -> list[SalesOrder]: """根据筛选条件查询订单列表,支持订单号、状态、客户名、手机号、业务员、工厂、来源、 时间范围等条件的模糊/精确匹配,并支持分页。 :param session: 数据库会话 :param filters: 筛选条件字典,可包含 order_no、order_status、customer_name、 customer_mobile、salesman_id、factory_id、order_source、 start_time、end_time、page_no、page_size 等键 :return: 字典,包含 total(总数)和 list(订单列表);若未传分页参数则 total 为 None 被 OrderService.list_orders 调用。 """ stmt = select(SalesOrder).where(SalesOrder.deleted == 0) if filters.get("order_no"): stmt = stmt.where(SalesOrder.order_no.contains(filters["order_no"])) if filters.get("order_status"): stmt = stmt.where(SalesOrder.order_status == filters["order_status"]) if filters.get("customer_name"): stmt = stmt.where(SalesOrder.customer_name.contains(filters["customer_name"])) if filters.get("customer_mobile"): stmt = stmt.where(SalesOrder.customer_mobile.contains(filters["customer_mobile"])) if filters.get("salesman_id") is not None: stmt = stmt.where(SalesOrder.salesman_id == filters["salesman_id"]) if filters.get("factory_id") is not None: stmt = stmt.where(SalesOrder.factory_id == filters["factory_id"]) if filters.get("order_source"): stmt = stmt.where(SalesOrder.order_source == filters["order_source"]) if filters.get("start_time"): start_time = datetime.strptime(filters["start_time"], "%Y-%m-%d %H:%M:%S") stmt = stmt.where(SalesOrder.created_at >= start_time) if filters.get("end_time"): end_time = datetime.strptime(filters["end_time"], "%Y-%m-%d %H:%M:%S") stmt = stmt.where(SalesOrder.created_at <= end_time) stmt = stmt.order_by(SalesOrder.id.desc()) page_no = filters.get("page_no") page_size = filters.get("page_size") if page_no is not None and page_size is not None: count_stmt = select(func.count()).select_from(stmt.subquery()) total = session.execute(count_stmt).scalar() or 0 offset = max(page_no - 1, 0) * page_size stmt = stmt.offset(offset).limit(page_size) rows = list(session.execute(stmt).scalars()) return {"total": total, "list": rows} return {"total": None, "list": list(session.execute(stmt).scalars())} def get_order(self, session: Session, order_id: int) -> SalesOrder | None: """根据 ID 获取单个订单详情。 :param session: 数据库会话 :param order_id: 订单主键 ID :return: 订单对象,不存在则返回 None 被 OrderService.get_order 等方法调用。 """ stmt = select(SalesOrder).where(SalesOrder.id == order_id, SalesOrder.deleted == 0) return session.execute(stmt).scalar_one_or_none() def get_supplier(self, session: Session, supplier_id: int | None) -> Supplier | None: """根据供应商 ID 获取供应商信息。 :param session: 数据库会话 :param supplier_id: 供应商主键 ID,为 None 时直接返回 None :return: 供应商对象,不存在则返回 None 被 OrderService 在查询订单时关联获取供应商信息调用。 """ if supplier_id is None: return None stmt = select(Supplier).where(Supplier.id == supplier_id, Supplier.deleted == 0) return session.execute(stmt).scalar_one_or_none() def list_order_items(self, session: Session, order_id: int) -> list[SalesOrderItem]: """查询指定订单下的所有订单明细项。 :param session: 数据库会话 :param order_id: 订单主键 ID :return: 订单明细项列表 被 OrderService.get_order、create_order 等方法调用。 """ stmt = select(SalesOrderItem).where(SalesOrderItem.order_id == order_id, SalesOrderItem.deleted == 0) return list(session.execute(stmt).scalars()) def create_order(self, session: Session, payload: dict, items: list[dict]) -> SalesOrder: """创建订单及其明细项(在一个事务中完成)。 :param session: 数据库会话 :param payload: 订单主表字段字典 :param items: 订单明细项字段字典列表 :return: 新创建的订单对象(含自增 ID 和关联的明细项) 被 OrderService.create_order 调用。 """ order = SalesOrder(**payload) session.add(order) session.flush() for item_payload in items: session.add(SalesOrderItem(order_id=order.id, **item_payload)) session.flush() return order def update_order_with_items(self, session: Session, order: SalesOrder, payload: dict, items: list[dict]) -> SalesOrder: """更新订单主表信息并替换其全部明细项(先删后插)。 :param session: 数据库会话 :param order: 待更新的订单对象 :param payload: 订单主表更新字段字典 :param items: 新的订单明细项字段字典列表(将完全替换原有明细) :return: 更新后的订单对象 被 OrderService.update_order 调用。 """ order.customer_id = payload["customer_id"] order.customer_name = payload["customer_name"] order.customer_mobile = payload["customer_mobile"] order.customer_address = payload.get("customer_address") order.salesman_id = payload.get("salesman_id") order.order_source = payload.get("order_source") order.delivery_type = payload.get("delivery_type") order.factory_id = payload.get("factory_id") order.sale_price_total = payload["sale_price_total"] order.cost_price_total = payload["cost_price_total"] order.rebate_total = payload["rebate_total"] order.freight_total = payload["freight_total"] order.tax_total = payload["tax_total"] order.other_fee_total = payload["other_fee_total"] order.profit_total = payload["profit_total"] order.profit_rate = payload["profit_rate"] order.commission_amount = payload["commission_amount"] order.remark = payload.get("remark") session.add(order) session.flush() session.query(SalesOrderItem).filter(SalesOrderItem.order_id == order.id, SalesOrderItem.deleted == 0).delete(synchronize_session=False) for item_payload in items: session.add(SalesOrderItem(order_id=order.id, **item_payload)) session.flush() return order def update_order_status(self, session: Session, order: SalesOrder, target_status: str) -> SalesOrder: """更新订单状态(用于流程流转)。 :param session: 数据库会话 :param order: 订单对象 :param target_status: 目标状态值 :return: 更新后的订单对象 被 OrderService 中各状态流转方法(approve、reject 等)调用。 """ order.order_status = target_status session.add(order) session.flush() return order def update_cancel_fields(self, session: Session, order: SalesOrder, payload: dict) -> SalesOrder: """更新订单的取消相关信息(取消请求发起时调用)。 :param session: 数据库会话 :param order: 订单对象 :param payload: 取消相关字段字典,包含 order_status、cancel_requested_by、 cancel_requested_at、cancel_reason、cancel_opinion、 cancel_previous_status 等键 :return: 更新后的订单对象 被 OrderService.cancel_order 调用。 """ order.order_status = payload["order_status"] order.cancel_requested_by = payload.get("cancel_requested_by") order.cancel_requested_at = payload.get("cancel_requested_at") order.cancel_reason = payload["cancel_reason"] order.cancel_opinion = payload.get("cancel_opinion") order.cancel_previous_status = payload.get("cancel_previous_status") session.add(order) session.flush() return order def clear_cancel_request(self, session: Session, order: SalesOrder) -> SalesOrder: """清除订单的取消请求信息(审批驳回取消请求时调用)。 :param session: 数据库会话 :param order: 订单对象 :return: 清除取消信息后的订单对象 被 OrderService.reject_cancel_order 调用。 """ order.cancel_requested_by = None order.cancel_requested_at = None order.cancel_reason = None order.cancel_opinion = None order.cancel_previous_status = None session.add(order) session.flush() return order def update_supplier_text_confirm(self, session: Session, order: SalesOrder, operator_id: int | None = None) -> SalesOrder: """确认供应商短信通知,将订单状态流转为 pending_factory(待工厂处理)。 :param session: 数据库会话 :param order: 订单对象 :param operator_id: 操作人 ID(可选) :return: 更新后的订单对象 被 OrderService.confirm_supplier_text 调用。 """ order.order_status = "pending_factory" order.supplier_text_confirmed_at = datetime.now() order.supplier_text_confirmed_by = operator_id session.add(order) session.flush() return order def create_supplier_text_log(self, session: Session, payload: dict) -> OrderSupplierTextLog: """创建供应商短信确认日志记录。 :param session: 数据库会话 :param payload: 日志字段字典 :return: 新创建的日志对象 被 OrderService.confirm_supplier_text 调用,记录短信确认操作。 """ log = OrderSupplierTextLog(**payload) session.add(log) session.flush() return log