# Settlement API 设计文档 ## 概述 本文档描述 settlement 模块的 API 设计,遵循项目 API 规范。 ## API 列表 ### 1. 开版订单统计 API 获取按客户分组的开版订单统计。 **基本信息**: - **URL**: `/api/v1/settlement/plate-orders/summary/` - **方法**: GET - **认证**: 需要认证 - **权限**: 需要关联商户 **请求参数**: | 参数名 | 类型 | 必填 | 说明 | 示例 | |--------|------|------|------|------| | date | string | 是 | 统计日期,格式 YYYY-MM-DD | 2026-02-08 | **请求示例**: ```http GET /api/v1/settlement/plate-orders/summary/?date=2026-02-08 HTTP/1.1 Authorization: Bearer ``` **响应示例**: ```json { "data": [ { "client_id": 101, "client_name": "客户A", "plate_order_count": [ { "type": "首版-定位", "today": 26, "current_month": 45 }, { "type": "修改-定位", "today": 3, "current_month": 7 }, { "type": "首版-匹布", "today": 3, "current_month": 7 } ] }, { "client_id": 102, "client_name": "客户B", "plate_order_count": [ { "type": "首版-定位", "today": 10, "current_month": 20 } ] } ] } ``` **响应字段说明**: | 字段名 | 类型 | 说明 | |--------|------|------| | data | array | 客户统计列表 | | data[].client_id | integer | 客户ID | | data[].client_name | string | 客户名称 | | data[].plate_order_count | array | 订单统计列表 | | data[].plate_order_count[].type | string | 类型组合(plate_type-production_method) | | data[].plate_order_count[].today | integer | 今日数量 | | data[].plate_order_count[].current_month | integer | 本月累计数量 | **业务规则**: 1. **商户隔离**: 只返回当前用户所属商户的数据 2. **客户可见性**: 应用客户可见性过滤 3. **过滤条件**: - `plate_type` 不为空的订单才纳入统计 - `production_method` 不为空的订单才纳入统计 4. **统计维度**: 按 `customer_id`、`customer_name`、`plate_type`、`production_method` 分组(同名客户不会被合并) 5. **today**: 指定日期当天的订单数量(基于 plate_date 字段) 6. **current_month**: 从当月1日(含)到指定日期(含)的订单数量 7. **数据过滤**: - 不返回没有数据的客户 - 客户中不显示全0数据的类型组合 **type 组合规则**: - 格式: `{plate_type}-{production_method}` - plate_type 可能的值: `首版`、`修改` - production_method 可能的值: `定位`、`匹布` - 组合示例: `首版-定位`、`首版-匹布`、`修改-定位`、`修改-匹布` **错误响应**: **400 Bad Request** - 缺少日期参数: ```json { "error": "缺少 date 参数" } ``` **400 Bad Request** - 日期格式错误: ```json { "error": "日期格式错误,请使用 YYYY-MM-DD 格式" } ``` **403 Forbidden** - 用户未关联商户: ```json { "error": "用户未关联商户" } ``` **403 Forbidden** - 日期不存在: ```json { "error": "日期不存在" } ``` --- ## 实现细节 ### View 层 - **文件**: `api_v1/views/settlement/views.py` - **类**: `PlateOrderSummaryView` - **继承**: `APIView` - **职责**: - 参数验证 - 商户隔离 - 调用 service 层 - 错误处理 ### Service 层 - **文件**: `settlement/services.py` - **函数**: `get_plate_order_summary_by_customer` - **职责**: - 复杂的统计逻辑 - 数据查询和聚合 - 数据格式化 ### URL 配置 - **文件**: `api_v1/urls.py` - **路由**: 添加到 settlement 路由组 --- ## 测试用例 ### 1. 正常情况 - 请求有效日期,返回正确数据 - 验证商户隔离 - 验证客户可见性过滤 - 验证 today 和 current_month 计算正确 ### 2. 边界情况 - 请求当月第一天(current_month = today) - 请求跨月日期 - 客户没有数据(不返回该客户) - 类型组合全0(不返回该类型) ### 3. 错误情况 - 日期格式错误 - 日期不存在(如 2026-02-30) - 用户未关联商户 ### 4. 数据过滤 - plate_type 为空的订单不纳入统计 - production_method 为空的订单不纳入统计 --- ## 性能考虑 1. **查询优化**: 使用 Django ORM 的 `annotate` 和聚合函数,避免 N+1 查询 2. **条件聚合**: 使用 `Case`/`When` 一次查询获取 today 和 current_month 3. **索引优化**: 确保 `plate_date`、`customer`、`plate_type`、`production_method` 字段有索引 4. **分页**: 暂不需要分页(数据量不大) ### 数据库优化评估记录(PostgreSQL) 1. 已评估索引、视图、物化视图等数据库层优化路线 2. 当前阶段暂不实施数据库结构优化,以保持线上稳定性 3. 生产环境不可接受阻塞风险:后续若加索引必须使用 `CREATE INDEX CONCURRENTLY`,并采用低峰分批策略 4. 优化上线前必须完成预发压测与 `EXPLAIN ANALYZE` 对比 --- ## 后续扩展 1. 支持日期范围查询(start_date, end_date) 2. 支持按商户过滤(管理员功能) 3. 支持导出 Excel 4. 支持缓存(Redis)