From 21898888e7781959f746b1fe6814f7353ab4810f Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期五, 21 八月 2026 17:03:14 +0800
Subject: [PATCH] 考勤记录下载模板 导入计算迟到加班正常打卡

---
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceRecordServiceImpl.java |   80 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 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..60ba60d 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
@@ -67,6 +67,86 @@
     }
 
     @Override
+    public void createImportedRecord(HrmAttendanceRecordDO record) {
+        // 鎸夎�冨嫟瑙勫垯閲嶇畻鎵撳崱绫诲瀷涓庢椂闀匡紝涓嶄俊浠� Excel 濉啓鐨勫��
+        fillClockTypes(record);
+        fillCalculatedHours(record);
+        attendanceRecordMapper.insert(record);
+    }
+
+    @Override
+    public void updateImportedRecord(HrmAttendanceRecordDO record) {
+        fillClockTypes(record);
+        fillCalculatedHours(record);
+        attendanceRecordMapper.updateById(record);
+    }
+
+    /**
+     * 鎸夎�冨嫟瑙勫垯閲嶇畻涓婁笅鐝墦鍗$被鍨嬶紙姝e父/杩熷埌/鏃╅��锛夛紝涓庢墦鍗¢�昏緫淇濇寔涓�鑷�
+     */
+    private void fillClockTypes(HrmAttendanceRecordDO record) {
+        if (record.getDeptId() == null) {
+            return;
+        }
+        HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(record.getDeptId());
+        if (rule == null) {
+            return;
+        }
+        // 涓婄彮鎵撳崱绫诲瀷锛氭櫄浜� 涓婄彮鏃堕棿+杩熷埌鍏佽 璁颁负杩熷埌
+        if (record.getClockInTime() != null && rule.getWorkStartTime() != null) {
+            int lateAllowMinutes = rule.getLateAllowMinutes() != null ? rule.getLateAllowMinutes() : 0;
+            LocalTime lateThreshold = rule.getWorkStartTime().plusMinutes(lateAllowMinutes);
+            LocalTime clockInOnly = record.getClockInTime().toLocalTime();
+            record.setClockInType(clockInOnly.isAfter(lateThreshold)
+                    ? HrmAttendanceClockTypeEnum.LATE.getType()
+                    : HrmAttendanceClockTypeEnum.NORMAL.getType());
+        }
+        // 涓嬬彮鎵撳崱绫诲瀷锛氭棭浜� 涓嬬彮鏃堕棿-鏃╅��鍏佽 璁颁负鏃╅��
+        if (record.getClockOutTime() != null && rule.getWorkEndTime() != null) {
+            int earlyAllowMinutes = rule.getEarlyAllowMinutes() != null ? rule.getEarlyAllowMinutes() : 0;
+            LocalTime earlyThreshold = rule.getWorkEndTime().minusMinutes(earlyAllowMinutes);
+            LocalTime clockOutOnly = record.getClockOutTime().toLocalTime();
+            record.setClockOutType(clockOutOnly.isBefore(earlyThreshold)
+                    ? HrmAttendanceClockTypeEnum.EARLY.getType()
+                    : HrmAttendanceClockTypeEnum.NORMAL.getType());
+        }
+    }
+
+    /**
+     * 鏍规嵁涓婁笅鐝墦鍗℃椂闂村拰鑰冨嫟瑙勫垯锛岃绠楀伐浣滄椂闀夸笌鍔犵彮鏃堕暱
+     */
+    private void fillCalculatedHours(HrmAttendanceRecordDO record) {
+        // 宸ヤ綔鏃堕暱 = 涓嬬彮鎵撳崱鏃堕棿 - 涓婄彮鎵撳崱鏃堕棿锛堜笌鎵撳崱閫昏緫涓�鑷达級
+        if (record.getClockInTime() != null && record.getClockOutTime() != null) {
+            Duration duration = Duration.between(record.getClockInTime(), record.getClockOutTime());
+            BigDecimal workHours = BigDecimal.valueOf(duration.toMinutes())
+                    .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
+            record.setWorkHours(workHours);
+        }
+        // 鍔犵彮鏃堕暱锛氭寜鑰冨嫟瑙勫垯鐨勬爣鍑嗕笅鐝椂闂磋绠楄秴棰濋儴鍒�
+        if (record.getClockOutTime() != null && record.getDeptId() != null) {
+            HrmAttendanceRuleDO rule = attendanceRuleService.getAttendanceRuleByDeptId(record.getDeptId());
+            if (rule != null && rule.getWorkEndTime() != null) {
+                LocalTime workEnd = rule.getWorkEndTime();
+                LocalDate outDate = record.getClockOutTime().toLocalDate();
+                LocalDateTime workEndDateTime = LocalDateTime.of(outDate, workEnd);
+                if (record.getClockOutTime().isAfter(workEndDateTime)) {
+                    Duration overtimeDuration = Duration.between(workEndDateTime, record.getClockOutTime());
+                    BigDecimal overtimeThreshold = rule.getOvertimeThreshold() != null
+                            ? rule.getOvertimeThreshold() : BigDecimal.ZERO;
+                    BigDecimal overtimeHours = BigDecimal.valueOf(overtimeDuration.toMinutes())
+                            .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);
+                    record.setOvertimeHours(overtimeHours.compareTo(overtimeThreshold) > 0 ? overtimeHours : BigDecimal.ZERO);
+                } else {
+                    record.setOvertimeHours(BigDecimal.ZERO);
+                }
+            } else {
+                record.setOvertimeHours(BigDecimal.ZERO);
+            }
+        }
+    }
+
+    @Override
     @Transactional(rollbackFor = Exception.class)
     public HrmAttendanceRecordDO clockIn(Long userId, LocalDateTime clockTime, String location) {
         LocalDate clockDate = clockTime.toLocalDate();

--
Gitblit v1.9.3