|
|
@@ -71,6 +71,7 @@ public class AttendanceStaffServiceImpl extends ServiceImpl<AttendanceStaffMappe
|
|
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
|
|
|
YearMonth yearMonth = YearMonth.parse(month, formatter);
|
|
|
LocalDate localDate = yearMonth.plusMonths(1).atDay(2);//查询条件
|
|
|
+ LocalDate localDate1 = yearMonth.plusMonths(0).atDay(1);//查询条件
|
|
|
|
|
|
LocalDate startDate = yearMonth.atDay(1);//本月开始日期
|
|
|
LocalDate endDate = yearMonth.atEndOfMonth();//本月结束日期
|
|
|
@@ -84,7 +85,7 @@ public class AttendanceStaffServiceImpl extends ServiceImpl<AttendanceStaffMappe
|
|
|
System.out.println("开始获取attendanceData==="+new Date().toString());
|
|
|
List<Attendance> attendanceList = attendanceService.list(new QueryWrapper<Attendance>()
|
|
|
.eq("month", month)
|
|
|
- .or().le("clock_time", localDate)
|
|
|
+ .or().and(i->i.ge("clock_time",localDate1).le("clock_time", localDate))
|
|
|
.orderByAsc("job_number","clock_time"));
|
|
|
System.out.println("开始获取applyFormList==="+new Date().toString());
|
|
|
//获取申请单数据
|
|
|
@@ -146,10 +147,7 @@ public class AttendanceStaffServiceImpl extends ServiceImpl<AttendanceStaffMappe
|
|
|
else if (applyForm.getType()==4){
|
|
|
//加班以实际打卡的时间和时长为准
|
|
|
List<Attendance> dayAttendance = attendances.stream().filter(a -> a.getClockTime().toLocalDate().equals(date)).collect(Collectors.toList());
|
|
|
- //7点之前的算是前一天的打卡时间
|
|
|
- dayAttendance = dayAttendance.stream().filter(a->a.getClockTime().toLocalTime().isAfter(LocalTime.of(7,0)))
|
|
|
- .sorted(Comparator.comparing(Attendance::getClockTime))
|
|
|
- .collect(Collectors.toList());
|
|
|
+ dayAttendance = resolveDayClockAttendances(date, dayAttendance, attendances);
|
|
|
if (dayAttendance.size() > 0) {
|
|
|
if (dayAttendance.size() == 1) {
|
|
|
staff.setClockStartTime(dayAttendance.get(0).getClockTime());
|
|
|
@@ -294,11 +292,12 @@ public class AttendanceStaffServiceImpl extends ServiceImpl<AttendanceStaffMappe
|
|
|
//白班或者异常小夜班,下班时间是当天
|
|
|
LocalDateTime endClockTime = null;
|
|
|
if (workTimeType.getAttendanceType() == JIA_BAN) {
|
|
|
- curDateAttendances.stream().filter(a->a.getClockTime().toLocalTime().isAfter(LocalTime.of(7, 0))).findFirst()
|
|
|
- .ifPresent(a->staff.setClockStartTime(a.getClockTime()));
|
|
|
- if (staff.getClockStartTime() != null) {
|
|
|
- endClockTime = curDateAttendances.stream().max(Comparator.comparing(Attendance::getClockTime)).get().getClockTime();
|
|
|
+ List<Attendance> effectiveDayAttendances = resolveDayClockAttendances(date, curDateAttendances, attendances);
|
|
|
+ if (effectiveDayAttendances.isEmpty()) {
|
|
|
+ continue;
|
|
|
}
|
|
|
+ staff.setClockStartTime(effectiveDayAttendances.get(0).getClockTime());
|
|
|
+ endClockTime = effectiveDayAttendances.get(effectiveDayAttendances.size() - 1).getClockTime();
|
|
|
}
|
|
|
else if (workTimeType.getAttendanceType().intValue() == BAI_BAN || workTimeType.getAttendanceType().intValue() == BAI_BAN_YI_CHANG_1 || workTimeType.getAttendanceType().intValue() == BAI_BAN_YI_CHANG_2 ||
|
|
|
workTimeType.getAttendanceType().intValue() == ZHONG_BAN || workTimeType.getAttendanceType().intValue() == XIAO_YE_BAN_YI_CHANG_1 || workTimeType.getAttendanceType().intValue() == XIAO_YE_BAN_YI_CHANG_2) {
|
|
|
@@ -340,6 +339,56 @@ public class AttendanceStaffServiceImpl extends ServiceImpl<AttendanceStaffMappe
|
|
|
return msg;
|
|
|
}
|
|
|
|
|
|
+ private static final LocalTime EARLY_MORNING_CUTOFF = LocalTime.of(7, 0);
|
|
|
+ private static final LocalTime NIGHT_SHIFT_START_THRESHOLD = LocalTime.of(16, 0);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析当天有效打卡:同日≥2次保留全部;仅1次凌晨卡且前日未闭合夜班则归前日下班。
|
|
|
+ */
|
|
|
+ private List<Attendance> resolveDayClockAttendances(LocalDate date, List<Attendance> dayAttendances, List<Attendance> allAttendances) {
|
|
|
+ if (dayAttendances == null || dayAttendances.isEmpty()) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ List<Attendance> sorted = dayAttendances.stream()
|
|
|
+ .sorted(Comparator.comparing(Attendance::getClockTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ if (sorted.size() >= 2) {
|
|
|
+ return sorted;
|
|
|
+ }
|
|
|
+ Attendance only = sorted.get(0);
|
|
|
+ if (!only.getClockTime().toLocalTime().isAfter(EARLY_MORNING_CUTOFF)
|
|
|
+ && isPreviousDayUnclosedNightShift(date, allAttendances, only.getClockTime())) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ return sorted;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 前一日末卡为晚班/夜班且未形成完整班次时,当日凌晨单卡视为前一日下班。
|
|
|
+ */
|
|
|
+ private boolean isPreviousDayUnclosedNightShift(LocalDate date, List<Attendance> allAttendances, LocalDateTime earlyPunch) {
|
|
|
+ LocalDate prevDate = date.minusDays(1);
|
|
|
+ List<Attendance> prevDay = allAttendances.stream()
|
|
|
+ .filter(a -> a.getClockTime().toLocalDate().equals(prevDate))
|
|
|
+ .sorted(Comparator.comparing(Attendance::getClockTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ if (prevDay.isEmpty()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (prevDay.size() >= 2) {
|
|
|
+ long hours = Duration.between(prevDay.get(0).getClockTime(), prevDay.get(prevDay.size() - 1).getClockTime()).toHours();
|
|
|
+ if (hours >= 8) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Attendance lastPrev = prevDay.get(prevDay.size() - 1);
|
|
|
+ if (lastPrev.getClockTime().toLocalTime().isBefore(NIGHT_SHIFT_START_THRESHOLD)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ long hoursSinceLastPrev = Duration.between(lastPrev.getClockTime(), earlyPunch).toHours();
|
|
|
+ return hoursSinceLastPrev < 8;
|
|
|
+ }
|
|
|
+
|
|
|
private AttendanceStaff getWorkTimeType(List<AttendanceRule> ruleList, List<Attendance> attendanceList) {
|
|
|
AttendanceRule baiBanRule = ruleList.get(0);
|
|
|
AttendanceRule yichangBaiBan1Rule = ruleList.get(1);
|