refactor(backend): 仓储层散参数收敛为查询 DTO
仓储层的 list_*/count_* 此前以 keyword/status/offset/limit 四五个散参数 传参,调用点重复铺开、易漏传且不可扩展;按项目「参数 >4 封装 DTO」的 约定统一收敛为各模块的 Query 对象(如 RoleQuery、BusinessQuery), 服务层与测试调用同步调整,行为不变。 - repositories 层查询方法签名改为 (session, query),分页与筛选条件 由 Query 承载,_apply_filters 同步收口 - schemas 层补齐各模块 Query 模型(approval/business_role/report 等) - services 层调用点同步改为传 Query - tests 随之调整;新增用例:待办角色流转(财务通过后领导出现待办)、 参数预览顺序稳定 验证:全量 pytest 900 passed(11:08);单元 526 passed;ruff check 绿。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
1 parent
c48d24ab6d
commit
5ece9f6dab
45 files changed
+1045
-1028
No files matched your search
@@ -9,7 +9,9 @@ from sqlalchemy.orm import Session
|
||||
from app.models import Customer, OwnershipChangeLog, Personnel
|
||||
from app.models.customer import OWNER_TYPE_CUSTOMER
|
||||
from app.repositories import ownership_log_repository
|
||||
from app.repositories.ownership_log_repository import OwnershipLogRef
|
||||
from app.repositories.query_utils import fuzzy
|
||||
from app.schemas.customer import CustomerQuery
|
||||
|
||||
# ==================== 读取 ====================
|
||||
|
||||
@@ -45,49 +47,25 @@ def get_by_company_owner(session: Session, company_name: str, owner_name: str) -
|
||||
return session.execute(stmt).scalar_one_or_none()
|
||||
|
||||
|
||||
def list_customers(
|
||||
session: Session,
|
||||
*,
|
||||
offset: int,
|
||||
limit: int,
|
||||
keyword: str | None = None,
|
||||
customer_type: str | None = None,
|
||||
owner_personnel_id: int | None = None,
|
||||
) -> list[Row]:
|
||||
def list_customers(session: Session, query: CustomerQuery) -> list[Row]:
|
||||
"""分页查询客户,行内容为 (客户, 归属人员姓名)。
|
||||
|
||||
归属人员外键非空但统一用 outerjoin:人员行不可考(被物理删除的脏数据)
|
||||
不应让客户行整个查不出来(同 personnel_repository 的韧性口径)。
|
||||
排序按 id 倒序:客户无排序字段,新增的靠前符合列表页习惯。
|
||||
"""
|
||||
stmt = _apply_filters(
|
||||
_base_select(),
|
||||
keyword=keyword,
|
||||
customer_type=customer_type,
|
||||
owner_personnel_id=owner_personnel_id,
|
||||
)
|
||||
stmt = stmt.order_by(Customer.id.desc()).offset(offset).limit(limit)
|
||||
stmt = _apply_filters(_base_select(), query)
|
||||
stmt = stmt.order_by(Customer.id.desc()).offset(query.offset).limit(query.page_size)
|
||||
return list(session.execute(stmt).all())
|
||||
|
||||
|
||||
def count_customers(
|
||||
session: Session,
|
||||
*,
|
||||
keyword: str | None = None,
|
||||
customer_type: str | None = None,
|
||||
owner_personnel_id: int | None = None,
|
||||
) -> int:
|
||||
def count_customers(session: Session, query: CustomerQuery) -> int:
|
||||
"""统计符合条件的客户总数,供分页使用。
|
||||
|
||||
筛选条件全部落在主表上,计数无需 join(列表与计数的筛选口径由
|
||||
``_apply_filters`` 单点保证)。
|
||||
"""
|
||||
stmt = _apply_filters(
|
||||
select(func.count(Customer.id)),
|
||||
keyword=keyword,
|
||||
customer_type=customer_type,
|
||||
owner_personnel_id=owner_personnel_id,
|
||||
)
|
||||
stmt = _apply_filters(select(func.count(Customer.id)), query)
|
||||
return int(session.execute(stmt).scalar_one())
|
||||
|
||||
|
||||
@@ -101,9 +79,7 @@ def list_ownership_logs(
|
||||
"""查某客户的归属变更留痕(共享实现,owner_type/customer_id 参数化)。"""
|
||||
return ownership_log_repository.list_by_ref(
|
||||
session,
|
||||
owner_type=OWNER_TYPE_CUSTOMER,
|
||||
ref_column=OwnershipChangeLog.customer_id,
|
||||
ref_id=customer_id,
|
||||
_customer_log_ref(customer_id),
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
)
|
||||
@@ -111,8 +87,12 @@ def list_ownership_logs(
|
||||
|
||||
def count_ownership_logs(session: Session, *, customer_id: int) -> int:
|
||||
"""统计某客户的归属留痕总数,供分页使用。"""
|
||||
return ownership_log_repository.count_by_ref(
|
||||
session,
|
||||
return ownership_log_repository.count_by_ref(session, _customer_log_ref(customer_id))
|
||||
|
||||
|
||||
def _customer_log_ref(customer_id: int) -> OwnershipLogRef:
|
||||
"""客户维度的归属留痕锚点。"""
|
||||
return OwnershipLogRef(
|
||||
owner_type=OWNER_TYPE_CUSTOMER,
|
||||
ref_column=OwnershipChangeLog.customer_id,
|
||||
ref_id=customer_id,
|
||||
@@ -126,20 +106,14 @@ def _base_select() -> Select:
|
||||
)
|
||||
|
||||
|
||||
def _apply_filters(
|
||||
stmt: Select,
|
||||
*,
|
||||
keyword: str | None,
|
||||
customer_type: str | None,
|
||||
owner_personnel_id: int | None,
|
||||
) -> Select:
|
||||
def _apply_filters(stmt: Select, query: CustomerQuery) -> Select:
|
||||
"""应用通用筛选条件。列表与计数共用,避免两处口径不一致。"""
|
||||
if keyword:
|
||||
stmt = stmt.where(_keyword_clause(keyword))
|
||||
if customer_type:
|
||||
stmt = stmt.where(Customer.customer_type == customer_type)
|
||||
if owner_personnel_id is not None:
|
||||
stmt = stmt.where(Customer.owner_personnel_id == owner_personnel_id)
|
||||
if query.keyword:
|
||||
stmt = stmt.where(_keyword_clause(query.keyword))
|
||||
if query.customer_type:
|
||||
stmt = stmt.where(Customer.customer_type == query.customer_type)
|
||||
if query.owner_personnel_id is not None:
|
||||
stmt = stmt.where(Customer.owner_personnel_id == query.owner_personnel_id)
|
||||
return stmt
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user