1
0
forked from erp-dev/erp
Files
erpnew/docs/settlement/Service.md

4.7 KiB
Raw Blame History

Settlement Service 设计文档

概述

本文档描述 settlement 模块的 service 层设计,遵循职责分离原则,每个函数职责单一、可测试。

函数列表

1. get_plate_order_summary_by_customer

获取按客户分组的开版订单统计。

参数:

  • merchant_id: int - 商户ID
  • settlement_date: datetime.date - 统计日期
  • user: User | None - 当前用户(用于客户可见性过滤)

返回:

  • list[dict] - 客户统计列表

职责:

  • 参数验证
  • 调用底层数据查询函数
  • 应用客户可见性过滤
  • 数据格式化

参数校验规则:

  • merchant_id 必须是正整数
  • settlement_date 必须是 datedatetime 类型(datetime 会自动转换为 date
  • 参数非法时抛出 ValueError

2. _get_plate_order_queryset

获取开版订单的基础查询集。

参数:

  • merchant_id: int - 商户ID
  • user: User | None - 当前用户(用于客户可见性过滤)

返回:

  • QuerySet[PlateOrder] - 过滤后的查询集

职责:

  • 应用商户隔离
  • 应用客户可见性过滤
  • 过滤 plate_type 不为空的订单
  • 过滤 production_method 不为空的订单
  • 优化查询select_related

3. _get_month_date_range

获取从月初到指定日期的日期范围。

参数:

  • settlement_date: datetime.date - 统计日期

返回:

  • tuple[date, date] - (月初日期, 统计日期)

职责:

  • 计算当月第一天
  • 返回日期范围元组

4. _aggregate_plate_orders_by_customer_and_type

按客户和类型分组聚合订单数据。

参数:

  • queryset: QuerySet[PlateOrder] - 基础查询集
  • settlement_date: datetime.date - 统计日期

返回:

  • QuerySet[PlateOrder] - 添加了聚合标注的查询集

职责:

  • 按 customer_id、customer_name、plate_type、production_method 分组
  • 计算今日数量(条件聚合)
  • 计算本月累计数量(条件聚合)
  • 生成 type 字段plate_type + '-' + production_method

5. _format_plate_order_summary

格式化聚合结果为 API 返回格式。

参数:

  • aggregated_data: QuerySet[PlateOrder] - 聚合后的查询集

返回:

  • list[dict] - 格式化后的数据

职责:

  • 遍历聚合结果
  • 按客户分组
  • 返回客户IDclient_id)和客户名称(client_name
  • 过滤全0数据
  • 生成最终的 API 返回格式

6. _filter_zero_data

过滤全0数据。

参数:

  • plate_order_counts: list[dict] - 订单统计列表

返回:

  • list[dict] - 过滤后的列表

职责:

  • 移除 today 和 current_month 都为 0 的数据

数据流程

get_plate_order_summary_by_customer
    ↓
_get_plate_order_queryset (获取基础查询集)
    ↓
_aggregate_plate_orders_by_customer_and_type (分组聚合)
    ↓
    _get_month_date_range (获取日期范围)
    ↓
_format_plate_order_summary (格式化结果)
    ↓
    _filter_zero_data (过滤全0数据)

过滤规则

  1. 商户隔离: 只查询指定商户的订单
  2. plate_type 过滤: plate_type 为空的订单不纳入统计
  3. production_method 过滤: production_method 为空的订单不纳入统计
  4. 客户可见性: 非超级用户只能看到自己创建的客户或被授权可见的客户
  5. 全0数据过滤: today 和 current_month 都为 0 的类型组合不返回
  6. 客户分组稳健性: 以 customer_id 分组,避免同名客户被合并

type 组合规则

格式: {plate_type}-{production_method}

plate_type 可能的值:

  • 首版
  • 修改

production_method 可能的值:

  • 定位
  • 匹布

组合示例:

  • 首版-定位
  • 首版-匹布
  • 修改-定位
  • 修改-匹布

测试策略

每个函数都应该有独立的单元测试:

  • _get_plate_order_queryset: 测试商户隔离、客户可见性过滤、plate_type 和 production_method 过滤
  • _get_month_date_range: 测试日期范围计算
  • _aggregate_plate_orders_by_customer_and_type: 测试分组聚合逻辑
  • _format_plate_order_summary: 测试数据格式化
  • _filter_zero_data: 测试全0数据过滤
  • get_plate_order_summary_by_customer: 集成测试

性能优化

  1. 使用 select_related 减少查询次数
  2. 使用 annotate 和聚合函数避免 N+1 查询
  3. 使用条件聚合Case/When一次查询获取 today 和 current_month

PostgreSQL 优化评估记录

  1. 已评估数据库层优化(索引、视图、物化视图)
  2. 当前决策:暂不实施结构性优化,优先保持线上稳定性
  3. 后续若优化,优先级为:索引 > 表达式索引 > 物化视图
  4. 生产约束:索引变更需使用并发建索引方式并在低峰执行