Browse Source

docs(academic): 写下「同一次匹配 ⇒ 同一份输出」纪律(detailId 与金额必须同源)

结课侧用教师档案算出教龄 → 匹配档 B(金额 20.00),溯源侧 lookupPayrollDetailID
又自己试算一遍且漏了教龄 → 返回档 A(detailId 显示 1)。两个字段都非空、类型都对,
只有对账时才会发现"金额与档位不是同一次决定的"。把这条固化为注释,并指明
TestFinishRecordResolvesTeacherExpFromProfile 必须同时断言 reward 与 detailId。
Q 9 hours ago
parent
commit
2adee30f34
1 changed files with 11 additions and 0 deletions
  1. 11 0
      internal/academic/service/course_query_service.go

+ 11 - 0
internal/academic/service/course_query_service.go

@@ -920,6 +920,17 @@ type RecordFinishView struct {
 
 // RecordViewService 结课响应装配服务(**只读**;不参与结账事务、不写任何表)。
 //
+// ⚠ **纪律(本类隐患的唯一防线)**:凡"同一次匹配产生多个输出"(金额 / 档位 / 费率 / 额度 / detailId),
+// **必须来自同一次匹配结果**,不要各算一遍。本项目已经踩过:
+//
+//	结课侧用"教师档案 → 教龄"匹配出档 B(金额 20.00),
+//	而溯源侧 `lookupPayrollDetailID` 自己又试算了一次、且没带教龄 ⇒ 返回档 A(detailId 显示 1)。
+//	两个字段都合法、都非空、类型都对,**只有对账时才会发现"金额与档位不是同一次决定的"**。
+//
+// 因此本文件里"金额"与"detailId"共用同一份入参口径(见 `lookupPayrollDetailID` 的注释),
+// 且用例 `TestFinishRecordResolvesTeacherExpFromProfile` 会同时断言 `payroll.reward` 与 `payroll.detailId`
+// 落在同一档 —— 只断言其中一个,这类缺陷仍然漏网。
+//
 // 为什么单独一个服务:`RecordService.FinishRecord` 的返回值只带"结账需要的数据"
 // (金额合计、逐学生明细),而契约还要求 `divide[]` 与 `payroll.detailId` 两个**溯源**字段。
 // 把它们塞进 FinishRecord(AC-11)会让结账事务多做两次无关查询、并在事务内做展示拼装;