GradingService
PAM 系統所有等第相關計算的單一來源。Controller 與各 fallback 一律呼叫此服務,禁止自行實作重複邏輯。
為什麼是樞紐
PAM 系統最容易出錯的地方是「計分公式散落在多處」——HrController 算一份、ReviewController 算一份、報表又算一份,遲早有一處不一致。GradingService 的設計核心就是「所有跟分數、等第、配額相關的決定都歸於一處」,新功能只能呼叫它,不能繞過它自己實作。它是整個 PAM 等第規則的 single source of truth;改公式只改這裡,所有下游服務(SettlementService、ReviewValidator、GradeReviewService)自動跟著變。
主要方法
| 方法 | 用途 |
|---|---|
CalcGrade(score) | 分數 → 等第(特優/優等/甲等/乙等/丙等) |
GradeRank(grade) | 等第 → 排序分數(比較大小用) |
ComputeScoreC(A, B, isMerged) | 當次平均分數 C(合併主管→C=A;否則 (A+B)/2) |
ComputeScoreD(A, B, isMerged, attendance) | 當次成績 D = C + 出勤扣分 |
ComputeAttendanceDeduction(hours) | 事假時數 → 扣分(每小時 -0.125) |
ComputeByRate(n) / QuotaSuggestion | 人數 → 建議配額(餘額法,sum 永遠 = n) |
GetSuggested(quota, grade) | 從 QuotaSuggestion 取對應等第建議數 |
CalcCeiling(...) | 等第天花板(懲處/假勤/年資 → 天花板等第 + 原因) |
CalcCeiling 是最複雜的——要綜合員工的懲處紀錄、假勤異常、年資長度,按優先序回傳該員的最高可達等第與限制原因(例如「事假超過 14 天 → 上限甲等」)。詳見 等第天花板。
設計原則
- 單一來源:HrController / ReviewController 的
CalculateGrade與各處 fallback 一律呼叫此服務 - 新功能不得重寫:需要等第判定或配額計算時,一律在 GradingService 補方法
- 方法純函數化:盡量無副作用,輸入相同則輸出相同——便於單元測試與快取
- 公式變動有審計:修改
CalcGrade區間或ComputeAttendanceDeduction倍率前,先在 等第規則 與 出勤扣分 文檔對齊,避免線上計分跟法規/HR 公告不一致
反模式(嚴禁)
- ❌ Controller 裡寫
score >= 90 ? "特優" : "優等"之類的硬式判斷 - ❌ 在 SQL 端用 CASE WHEN 算等第(前後端不一致)
- ❌ 為了「特殊情境」複製一份 GradingService 改一個分支
- ❌ 在 Hrms104Repository 或其他資料層計算分數
發現上述模式 → 立刻把該邏輯抽回 GradingService 補一個對應方法。
核心公式
C = (A + B) / 2 若 R1 ≠ R2
C = A 若 R1 = R2(合併)
D = C + 出勤扣分 // 出勤扣分 ≤ 0
誰在用 GradingService
- ReviewValidator — 提交前驗證分數合法性
- SettlementService — 年度結算消費此服務算最終等第
- GradeReviewService — 等第審核流程的計算後盾
- HrController / ReviewController — 直接 API 呼叫
- 強制具體事蹟 / 等第分配自動平衡 — 用
QuotaSuggestion推薦配額
相關概念
強連結(原文明確提及)
- 等第規則 — 五等第分數區間與比率
- 等第天花板 —
CalcCeiling邏輯 - 出勤扣分 —
ComputeAttendanceDeduction公式 - 分數精度 — 0.125 倍數的精度需求
- ReviewValidator — 提交前驗證
- SettlementService — 年度結算消費此服務
- GradeReviewService — 等第審核服務
- 等第分配自動平衡 — TryAutoBalanceCounts 用此服務
- 強制具體事蹟 — 配額建議來自此服務
推斷連結(LLM 認為相關,待確認)
- 獎懲加減分 ?? — 計分組成可能用到
- GradeAdjustment ?? — 調分流向此服務
深入閱讀(外部資源)
← 回到 wiki