增量质量报告 · huanyan/server
- 版本区间:
v0.1.41(base d42e172 → head 572cb5e)
- 分支:
v0.1.41
- 报告口径:本报告「修复 / 新增」章节严格取自
codescan.issues_diff(base..head)真实数据;变更面取自 codescan.git_diff;无编造。
一、变更概览
本轮是 D61「开单拆单」波 A 的一次大版本落地,同时收口了员工端(mp)波 C 补口与报表成交口径。变更文件共 46 个(其中新增 11 个源文件)。
1.1 主题一:开单拆单(D61)
新增「销售单 / 服务单」双单据类型与「待支付 → 收款成立 → 服务生命周期」状态机:
| 类别 | 新增/修改 | 说明 |
|---|
| 实体 | entities/order.rs(+kind/draft_allocs/draft_pay_intent)、新增 entities/service_order.rs、entities/order_item_staff.rs | 单据类型、服务单卫星、行级服务人(「谁做了哪个项目」唯一口径) |
| 迁移 | 新增 m20261016_000023_order_split、_000024_order_status、_000025_draft_pay_intent | 表 61→63;状态 CHECK 扩六态;幂等 DDL |
| 开单域 | 新增 sale/order_draft.rs(建单·零账本)、sale/settle.rs(结算成立共享内核)、sale/service_flow.rs(cancel/start/finish)、sale/pending.rs(待收款清单);改写 sale/create.rs、sale/query.rs、sale/void.rs、sale/treatment.rs、sale/status.rs | POST /orders = 建「待支付」单 + 立即结算;幂等闸 = 条件更新 status='待支付' |
1.2 主题二:报表 / 客户域的「成交口径」收口
将散落的硬编码 status = '已完成' 统一切到 sale::status::{active_statuses, service_record_statuses, finished_statuses}:
crm/list.rs、followup/service.rs、report/{overview,conversion,recharge_consume,usage,components}.rs。
其中 report/conversion.rs 的多段裸 SQL 拼接改为 SeaORM 子查询(消除一处 Critical SQL 注入告警,见 §二)。
1.3 测试
新增 tests/order_split.rs(~4485 行,覆盖 Task 1–11 与复审 H1/L/M 系列),并在 tests/app_employee.rs 扩充 app 通道四条链路测试;tests/archive_read.rs、tests/version_release.rs 做共享测试库可重跑改造。
二、修复的问题(真实数据:共 64 条)
⚠️ 数据说明:issues_diff 按「文件 + 严重度 + 类型 + 描述」比对。本轮为大规模重构,大量条目属于函数位移导致的行号变化(base 某行问题消失、head 对应内容出现在新行号),并非独立缺陷修复。下表只列出可确认的真实修复,其余归属「重构位移」。
2.1 真实修复(可确认)
| 严重度 | 位置 | 问题 | 说明 |
|---|
| Critical/Security | src/modules/report/conversion.rs:537(base) | SQL 注入风险 | 本轮真实修复:conversion.rs 中 cohort_members / convert_map / visit_ids / all_visit_first_times / all_history_converted / chain_customers 等全部裸 SQL 拼接改写为 SeaORM 子查询(in_subquery / into_tuple / paginate),描述文案统一走 components。这是本轮最有价值的安全修复。 |
| Medium/Complexity | src/modules/crm/list.rs:155/238 | 函数过长 / 圈复杂度 | conversion_subquery_sql() 裸 SQL → conversion_customer_subquery()(SeaORM),并抽出 customer_and_creator_names 等,原超长函数被拆分。 |
| Medium/Complexity | 等 |
2.2 归为「重构位移」的条目
func_keys.rs:40、card/object.rs:356/500、crm/list.rs:261、followup/service.rs:149/320、sale/create.rs 多处、sale/query.rs、sale/treatment.rs、router.rs:238/350/356、tests/archive_read.rs 若干 —— 这些在 head 的对应位置仍以新行号存在(见 §三),不构成净减少。
净效果:Critical 由 7 → 6(report/conversion.rs 那处注入被真实消除),High 级 0 条。
三、新增问题(真实数据:共 461 条)
严重度构成:新增 0 个 Critical、0 个 High,全部为 Medium/Low。绝大多数为复杂度/耦合/unwrap/测试夹具 SQL 的静态告警。
3.1 生产代码(src/)— 需要关注
(A)超长函数 / 高复杂度(可维护性 + 回归风险,最值得关注)
| 位置 | 问题 |
|---|
src/modules/sale/settle.rs:92 | settle_core 圈复杂度 28 / 嵌套深 / 455 行 / fan-out 107 |
src/modules/sale/create.rs:509 | validate_req 圈复杂度 94 / 663 行 |
src/modules/crm/list.rs:282 | assemble_rows 圈复杂度 27 / 321 行 |
src/modules/sale/query.rs:512 | order_detail 251 行 |
src/modules/app/order_aux.rs:300 | usage_quota 圈复杂度 13 / 138 行 |
src/modules/app/order_aux.rs:504 | out_products_preview 97 行 |
src/modules/sale/settle.rs:822 | settle_inner 133 行 |
(B)工具判定的「高耦合 / 扇入扇出异常」(多为新模块依赖面大,非缺陷,但提示拆分)
settle.rs(settle_core/settle_inner/load_draft_allocs/load_line_staffs/normalize_allocs/execute_stock_out/deduct_balance/upsert_balance_account/insert_service_satellites)、app/order_aux.rs、app/my_orders.rs:119、app/my_services.rs:93、app/staff_options.rs:60、crm/list.rs:141、report/conversion.rs:53/181/212/248、followup/service.rs:74、card/object.rs:340、inventory/mod.rs:157。
(C)重复代码块(可抽公共函数)
src/middlewares/app_auth.rs:155(AppFuncGuardAny 与 AppFuncGuard 逻辑重复)、card/object.rs:428、order_aux.rs:99/109、crm/list.rs:305、followup/service.rs:348、report/conversion.rs:186/200、sale/create.rs:614/618、sale/order_draft.rs:297、sale/query.rs:314、sale/service_flow.rs:78/114、sale/settle.rs:212/222/323、sale/treatment.rs:76/111、router.rs:312/411。
(D)其它
Low/Maintainability 行过长:migration/m20261016_000024、my_orders.rs:47、my_services.rs:212、order_aux.rs:104、staff_options.rs:58、order_draft.rs:95、pending.rs:52、query.rs:237、service_flow.rs:57、settle.rs:809、create.rs:1693 等。
Low/Dependency 公开字段过多:service_order.rs:10、my_orders.rs:93、my_services.rs:51、create.rs:154、card/object.rs:572、report/conversion.rs:117。
Low 参数过多:my_orders.rs:119(9)、query.rs:239(11)、report/conversion.rs:669(10)。
Low 注释代码过多:create.rs:117、settle.rs:130。
Low 待办标记:src/modules/sale/create.rs:1445(kind 兼容窗口的 TODO(波B/C 收口),属的计划性标记,非缺陷)。
3.2 测试代码(tests/)— 数量占新增中的绝大部分
unwrap() 无安全注释:tests/app_employee.rs(约 30+ 处)、tests/order_split.rs(约 90+ 处)、tests/archive_read.rs(多处)。均位于测试断言/夹具路径,属工具规则(要求 // SAFETY: 注释)触发,非生产缺陷。
- SQL 字符串拼接告警:
tests/app_employee.rs、tests/order_split.rs、tests/archive_read.rs 的夹具 INSERT/UPDATE/DELETE。测试夹具常量拼接,无外部输入注入面。
- 长函数 / 高耦合:
tests/order_split.rs 的 cleanup(115 行)、fixture(161 行)、各 #[tokio::test] 用例(多为 90–330 行);tests/app_employee.rs 的 aux_seed(301 行)、app_order_channel_flow(329 行)等。
四、存量遗留(base 即有、本轮未消除)
head 仍有 6 条 Critical/Security「SQL 注入风险」(base 为 7 条,本轮消除 1 条):
| 位置 | 判定 |
|---|
src/modules/report/usage.rs:236/237/256 | 四类消耗事件 UNION ALL 异构投影的参数化裸 SQL(值为 $n 绑定);本轮仅在其中补 components::active_status_sql() 状态集,未改结构 |
src/modules/report/recharge_consume.rs:302 | 同上(四类型交易 UNION ALL) |
src/modules/card/category.rs:510 | 未改动 |
src/modules/inventory/by_product.rs:54 | 未改动 |
本批 diff 在 usage.rs / recharge_consume.rs 顶部新增了明确的例外说明注释(AGENTS 约束 6 例外:sea-query 1.0.2 无 JOIN LATERAL / 数组子查询 builder API,逐列只能 Expr::cust,等价于 raw SQL 换壳且放大回归面),值一律 $n 绑定、无注入面。建议将这几处登记为已知例外,避免每次扫描重复告警。
五、风险点与建议
-
超大内核函数的回归风险(最高优先级)
settle_core(455 行 / 复杂度 28)、validate_req(663 行 / 复杂度 94)、assemble_rows(321 行 / 复杂度 27)承载「建单+结算+账本+库存+分摊」全部不变式。虽已有 tests/order_split.rs 覆盖(幂等/并发/零账本/镜像一致),但函数规模使局部修改的爆炸半径很大。建议按 §3.1(A) 逐步抽出(如把 settle_core 的「账本写入 ①–⑩」按段拆成子函数,保留同一事务)。
-
状态口径必须全库收口,防漏计
拆单引入 待服务/服务中/已完成/待支付/已取消 六态后,任何残留的硬编码 '已完成' 都会静默漏计服务单。本轮已把 crm/list、followup、report/*、sale/* 的取数切到 sale::status,建议再做一次全库审计(搜索字符串字面量 已完成、已作废),确保后续读取点一律走 sale::status。同时注意四个口径互不相同:
- 成交/营业额/消费记录 =
active_statuses()(待服务/服务中/已完成)
- 我的服务「待服务档」=
wait_service_statuses()(含待支付)
- 客户「服务记录」=
service_record_statuses()(服务中/已完成,不含待服务)
- 回访候选/待回访 =
finished_statuses()(仅已完成)
-
金额单位双轨制的契约风险
新增 , 一律整数()、后台维持。混用会直接造成 100 倍资损。建议:把 app 通道 字段纳入契约测试(已有 断言),并在 code review 检查清单固化「 新增金额字段必须 + 命名」。
六、结论
- 本轮为功能性大版本(拆单波 A),一次引入 11 个新源文件与 3 个迁移;新增问题全部为 Medium/Low 的复杂度、耦合与测试卫生类,未新增 Critical/High 安全或正确性缺陷。
- 修复方面:真实消除了 1 处 Critical(
report/conversion.rs 裸 SQL → SeaORM),并借重构消解了 crm/list.rs、sale/create.rs 的多处复杂度告警;其余 63 条「修复」多为函数位移。
- 最需跟进的三件事:① 拆分
settle_core/validate_req 等超大内核;② 全库审计残留硬编码状态串;③ 固化 app 通道「分」单位契约与已知 SQL 例外白名单。