264 lines
12 KiB
Python
264 lines
12 KiB
Python
"""
|
||
订单数据访问层。
|
||
|
||
负责封装销售订单(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("order_type"):
|
||
stmt = stmt.where(SalesOrder.order_type == filters["order_type"])
|
||
if filters.get("need_invoice") is not None:
|
||
stmt = stmt.where(SalesOrder.need_invoice == filters["need_invoice"])
|
||
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.contract_amount = payload.get("contract_amount", 0)
|
||
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.payment_method = payload.get("payment_method")
|
||
order.tax_amount = payload.get("tax_amount", 0)
|
||
order.need_invoice = payload.get("need_invoice", 0)
|
||
order.order_type = payload.get("order_type")
|
||
order.self_delivery = payload.get("self_delivery", 0)
|
||
order.tracking_number = payload.get("tracking_number")
|
||
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_logistics(待绑定物流单号)。
|
||
|
||
:param session: 数据库会话
|
||
:param order: 订单对象
|
||
:param operator_id: 操作人 ID(可选)
|
||
:return: 更新后的订单对象
|
||
被 OrderService.confirm_supplier_text 调用。
|
||
"""
|
||
order.order_status = "pending_logistics"
|
||
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
|