From b852254d90e7d1955db31db154193ec8ee84d8b3 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 09 九月 2026 10:57:59 +0800
Subject: [PATCH] feat(hrm): 新增员工用工性质、班组归属字段及考勤异常处理优化

---
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 56 insertions(+), 1 deletions(-)

diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java
index f7ff44c..0d03bbd 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java
+++ b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java
@@ -173,8 +173,59 @@
                     .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
             record.setWorkHours(workHours);
         }
+        // 7. 璁$畻鍔犵彮鏃堕暱锛氳秴杩囪鍒欎笅鐝椂闂寸殑閮ㄥ垎
+        record.setOvertimeHours(computeOvertimeHours(rule.getWorkEndTime(), clockTimeOnly));
         attendanceRecordMapper.updateById(record);
         return record;
+    }
+
+    /**
+     * 璁$畻鍔犵彮鏃堕暱锛堝皬鏃讹級锛歝lockTimeOnly 鏅氫簬 workEndTime 鐨勯儴鍒嗭紝鍚﹀垯涓� 0
+     */
+    private BigDecimal computeOvertimeHours(LocalTime workEndTime, LocalTime clockTimeOnly) {
+        if (workEndTime == null || clockTimeOnly == null || !clockTimeOnly.isAfter(workEndTime)) {
+            return BigDecimal.ZERO;
+        }
+        return BigDecimal.valueOf(Duration.between(workEndTime, clockTimeOnly).toMinutes())
+                .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void recordOvertime(HrmAttendanceExceptionDO exception) {
+        // 浠呭鐞嗗姞鐝被鍨�
+        if (!HrmAttendanceExceptionTypeEnum.OVERTIME.getType().equals(exception.getType())
+                || exception.getExceptionTime() == null) {
+            return;
+        }
+        // 1. 鍙栧憳宸ヨ�冨嫟瑙勫垯锛岀敤瑙勫垯涓嬬彮鏃堕棿鍒板紓甯告椂闂�(瀹為檯涓嬬彮鐐�)鎶樼畻鍔犵彮鏃堕暱锛涙棤瑙勫垯鍒欐棤娉曟姌绠楋紝璺宠繃
+        BigDecimal overtimeHours = BigDecimal.ZERO;
+        HrmEmployeeDO employee = employeeService.getEmployee(exception.getUserId());
+        HrmAttendanceRuleDO rule = employee == null ? null
+                : attendanceRuleService.getAttendanceRuleByDeptId(employee.getDeptId());
+        if (rule != null) {
+            overtimeHours = computeOvertimeHours(rule.getWorkEndTime(), exception.getExceptionTime().toLocalTime());
+        }
+        if (overtimeHours.compareTo(BigDecimal.ZERO) <= 0) {
+            return;
+        }
+        // 2. 鏌ヨ褰撴棩鑰冨嫟璁板綍锛屼笉瀛樺湪鍒欒ˉ寤�
+        HrmAttendanceRecordDO record = attendanceRecordMapper.selectByUserIdAndDate(exception.getUserId(), exception.getExceptionDate());
+        if (record == null) {
+            record = HrmAttendanceRecordDO.builder()
+                    .userId(exception.getUserId())
+                    .deptId(employee != null ? employee.getDeptId() : exception.getDeptId())
+                    .date(exception.getExceptionDate())
+                    .dataSource(HrmAttendanceDataSourceEnum.SUPPLEMENT.getType())
+                    .build();
+            record.setOvertimeHours(overtimeHours);
+            attendanceRecordMapper.insert(record);
+            return;
+        }
+        // 3. 宸叉湁璁板綍鍒欑疮鍔犲姞鐝椂闀�
+        BigDecimal existed = record.getOvertimeHours() != null ? record.getOvertimeHours() : BigDecimal.ZERO;
+        record.setOvertimeHours(existed.add(overtimeHours));
+        attendanceRecordMapper.updateById(record);
     }
 
     @Override
@@ -187,11 +238,13 @@
         LocalDate exceptionDate = exception.getExceptionDate();
         LocalDateTime exceptionTime = exception.getExceptionTime();
         Long userId = exception.getUserId();
+        HrmEmployeeDO employee = employeeService.getEmployee(userId);
+        HrmAttendanceRuleDO rule = employee == null ? null
+                : attendanceRuleService.getAttendanceRuleByDeptId(employee.getDeptId());
         // 鏌ヨ鑰冨嫟璁板綍
         HrmAttendanceRecordDO record = attendanceRecordMapper.selectByUserIdAndDate(userId, exceptionDate);
         if (record == null) {
             // 濡傛灉娌℃湁璁板綍锛屽垱寤轰竴鏉�
-            HrmEmployeeDO employee = employeeService.getEmployee(userId);
             record = HrmAttendanceRecordDO.builder()
                     .userId(userId)
                     .deptId(employee != null ? employee.getDeptId() : exception.getDeptId())
@@ -210,6 +263,8 @@
             // 涓嬬彮琛ュ崱
             record.setClockOutTime(exceptionTime);
             record.setClockOutType(HrmAttendanceClockTypeEnum.NORMAL.getType());
+            // 涓嬬彮琛ュ崱鍚屾椂鎶樼畻鍔犵彮鏃堕暱锛堣秴杩囪鍒欎笅鐝椂闂撮儴鍒嗭級
+            record.setOvertimeHours(computeOvertimeHours(rule == null ? null : rule.getWorkEndTime(), time));
         }
         // 鏇存柊鏁版嵁鏉ユ簮涓鸿ˉ鍗″鎵�
         record.setDataSource(HrmAttendanceDataSourceEnum.SUPPLEMENT.getType());

--
Gitblit v1.9.3