Browse Source

fix(backend): 统一评分为 OKR 60 + 绩效 40 并增加边界测试

wangkangyjy 1 week ago
parent
commit
f8b15b3e9a

+ 5 - 5
backend/src/main/java/com/yimeng/okr/config/DataInitializer.java

@@ -116,11 +116,11 @@ public class DataInitializer implements CommandLineRunner {
         long count = dimensionMapper.selectCount(null);
         if (count > 0) return;
 
-        seedDimension("交付质量", 15, 1);
-        seedDimension("协作沟通", 15, 2);
-        seedDimension("学习成长", 15, 3);
-        seedDimension("创新贡献", 15, 4);
-        log.info("Assessment dimensions seeded: 4 (total 60)");
+        seedDimension("交付质量", 10, 1);
+        seedDimension("协作沟通", 10, 2);
+        seedDimension("学习成长", 10, 3);
+        seedDimension("创新贡献", 10, 4);
+        log.info("Assessment dimensions seeded: 4 (total 40)");
     }
 
     private void seedDimension(String name, int maxScore, int sortOrder) {

+ 2 - 2
backend/src/main/java/com/yimeng/okr/service/PerformanceService.java

@@ -333,8 +333,8 @@ public class PerformanceService {
     }
 
     private void validateScoreParts(Double okrScore, Double kpiScore, Double bonus, Double penalty) {
-        requireRange("OKR得分", okrScore, 0, 40);
-        requireRange("KPI得分", kpiScore, 0, 60);
+        requireRange("OKR得分", okrScore, 0, 60);
+        requireRange("绩效维度得分", kpiScore, 0, 40);
         requireRange("加分", bonus != null ? bonus : 0, 0, 20);
         requireRange("扣分", penalty != null ? penalty : 0, 0, 20);
         double total = calculateTotal(okrScore, kpiScore, bonus, penalty);

+ 32 - 11
backend/src/test/java/com/yimeng/okr/service/PerformanceServiceTest.java

@@ -35,16 +35,37 @@ class PerformanceServiceTest {
     @InjectMocks PerformanceService performanceService;
 
     @Test
-    void submitSelfScoreRejectsOkrScoreAboveForty() {
+    void submitSelfScoreRejectsOkrScoreAboveSixty() {
         when(periodMapper.selectById(1L)).thenReturn(period());
 
         BusinessException ex = assertThrows(BusinessException.class,
-                () -> performanceService.submitSelfScore(1L, 2L, 41.0, 50.0, 0.0, 0.0, "{}"));
+                () -> performanceService.submitSelfScore(1L, 2L, 61.0, 30.0, 0.0, 0.0, "{}"));
 
         assertTrue(ex.getMessage().contains("OKR"));
         verify(scoreMapper, never()).insert(any());
     }
 
+    @Test
+    void submitSelfScoreRejectsKpiScoreAboveForty() {
+        when(periodMapper.selectById(1L)).thenReturn(period());
+
+        BusinessException ex = assertThrows(BusinessException.class,
+                () -> performanceService.submitSelfScore(1L, 2L, 50.0, 41.0, 0.0, 0.0, "{}"));
+
+        assertTrue(ex.getMessage().contains("绩效"));
+        verify(scoreMapper, never()).insert(any());
+    }
+
+    @Test
+    void submitSelfScoreAcceptsOkr60Kpi40Max() {
+        when(periodMapper.selectById(1L)).thenReturn(period());
+        when(userMapper.selectById(2L)).thenReturn(user(2L, null));
+        when(scoreMapper.insert(any())).thenReturn(1);
+
+        assertDoesNotThrow(() ->
+                performanceService.submitSelfScore(1L, 2L, 60.0, 40.0, 0.0, 0.0, "{}"));
+    }
+
     @Test
     void getScoringPageRequiresViewPermission() {
         doThrow(new BusinessException(403, "无权查看"))
@@ -65,7 +86,7 @@ class PerformanceServiceTest {
         finalScore.setEvaluatorId(3L);
         finalScore.setType(ScoreType.FINAL);
         finalScore.setOkrScore(30.0);
-        finalScore.setKpiScore(50.0);
+        finalScore.setKpiScore(30.0);
         finalScore.setBonus(0.0);
         finalScore.setPenalty(0.0);
         finalScore.setTotal(80.0);
@@ -73,7 +94,7 @@ class PerformanceServiceTest {
         when(authorizationService.isHrOrAbove(99L)).thenReturn(true);
 
         PerformanceScore corrected = performanceService.correctFinalScore(
-                11L, 99L, 35.0, 55.0, 0.0, 0.0, "{\"note\":\"修正\"}", "复核通过");
+                11L, 99L, 55.0, 35.0, 0.0, 0.0, "{\"note\":\"修正\"}", "复核通过");
 
         assertEquals(90.0, corrected.getTotal());
         verify(auditCorrectionMapper).insert(argThat(audit ->
@@ -97,7 +118,7 @@ class PerformanceServiceTest {
         when(authorizationService.isHrOrAbove(99L)).thenReturn(true);
 
         PerformanceScore corrected = performanceService.correctFinalScore(
-                11L, 99L, 35.0, 55.0, 0.0, 0.0, "{}", "确认后修正");
+                11L, 99L, 55.0, 35.0, 0.0, 0.0, "{}", "确认后修正");
 
         assertEquals("PENDING_PUBLISH", corrected.getStatus());
         assertNull(corrected.getConfirmedAt());
@@ -119,7 +140,7 @@ class PerformanceServiceTest {
         when(authorizationService.isHrOrAbove(99L)).thenReturn(true);
 
         PerformanceScore corrected = performanceService.correctFinalScore(
-                12L, 99L, 35.0, 55.0, 0.0, 0.0, "{}", "复核修正");
+                12L, 99L, 55.0, 35.0, 0.0, 0.0, "{}", "复核修正");
 
         assertEquals("PENDING_PUBLISH", corrected.getStatus());
         assertNull(corrected.getPublishedAt());
@@ -136,7 +157,7 @@ class PerformanceServiceTest {
         when(scoreMapper.selectOne(any())).thenReturn(null);
 
         BusinessException ex = assertThrows(BusinessException.class,
-                () -> performanceService.submitSuperiorScore(1L, 2L, 3L, 30.0, 50.0, 0.0, 0.0, "{}"));
+                () -> performanceService.submitSuperiorScore(1L, 2L, 3L, 50.0, 30.0, 0.0, 0.0, "{}"));
 
         assertTrue(ex.getMessage().contains("自评"));
         verify(scoreMapper, never()).insert(any());
@@ -152,7 +173,7 @@ class PerformanceServiceTest {
         when(userMapper.selectById(3L)).thenReturn(evaluator);
 
         BusinessException ex = assertThrows(BusinessException.class,
-                () -> performanceService.submitSuperiorScore(1L, 2L, 3L, 30.0, 50.0, 0.0, 0.0, "{}"));
+                () -> performanceService.submitSuperiorScore(1L, 2L, 3L, 50.0, 30.0, 0.0, 0.0, "{}"));
 
         assertTrue(ex.getMessage().contains("评分人"));
         verify(scoreMapper, never()).insert(any());
@@ -166,7 +187,7 @@ class PerformanceServiceTest {
         when(userMapper.selectById(2L)).thenReturn(target);
 
         BusinessException ex = assertThrows(BusinessException.class,
-                () -> performanceService.submitSuperiorScore(1L, 2L, 3L, 30.0, 50.0, 0.0, 0.0, "{}"));
+                () -> performanceService.submitSuperiorScore(1L, 2L, 3L, 50.0, 30.0, 0.0, 0.0, "{}"));
 
         assertTrue(ex.getMessage().contains("被评分人"));
         verify(scoreMapper, never()).insert(any());
@@ -180,7 +201,7 @@ class PerformanceServiceTest {
         PerformanceScore selfScore = score(ScoreType.SELF, "SELF_SUBMITTED");
         when(scoreMapper.selectOne(any())).thenReturn(selfScore, null);
 
-        performanceService.submitSuperiorScore(1L, 2L, 3L, 30.0, 50.0, 0.0, 0.0, "{}");
+        performanceService.submitSuperiorScore(1L, 2L, 3L, 50.0, 30.0, 0.0, 0.0, "{}");
 
         ArgumentCaptor<PerformanceScore> captor = ArgumentCaptor.forClass(PerformanceScore.class);
         verify(scoreMapper, times(2)).insert(captor.capture());
@@ -243,7 +264,7 @@ class PerformanceServiceTest {
         score.setType(type);
         score.setStatus(status);
         score.setOkrScore(30.0);
-        score.setKpiScore(50.0);
+        score.setKpiScore(30.0);
         score.setBonus(0.0);
         score.setPenalty(0.0);
         score.setTotal(80.0);