| | |
| | | package cn.iocoder.yudao.module.hrm.service.attendance; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceSummaryPageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceHolidayDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceRecordDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceSummaryDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmAttendanceRecordMapper; |
| | | import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmAttendanceSummaryMapper; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAttendanceClockTypeEnum; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAttendanceHolidayTypeEnum; |
| | | import cn.iocoder.yudao.module.hrm.service.employee.HrmEmployeeService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.DayOfWeek; |
| | | import java.time.LocalDate; |
| | | import java.time.YearMonth; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 考勤统计汇总 Service 实现类 |
| | |
| | | |
| | | /** |
| | | * 计算应出勤天数(工作日数量) |
| | | * |
| | | * 一次取出区间内节假日配置,避免逐日查询。 |
| | | */ |
| | | private int calculateWorkDays(LocalDate startDate, LocalDate endDate) { |
| | | Map<LocalDate, Integer> holidayTypeMap = attendanceHolidayService |
| | | .getAttendanceHolidayListByDateRange(startDate, endDate) |
| | | .stream() |
| | | .collect(Collectors.toMap(HrmAttendanceHolidayDO::getDate, HrmAttendanceHolidayDO::getType, |
| | | (a, b) -> a)); |
| | | int workDays = 0; |
| | | LocalDate current = startDate; |
| | | while (!current.isAfter(endDate)) { |
| | | if (attendanceHolidayService.isWorkDay(current)) { |
| | | Integer holidayType = holidayTypeMap.get(current); |
| | | boolean work; |
| | | if (holidayType != null) { |
| | | // 有节假日配置时按配置判断:休息日不算应出勤,工作日计入(含调休上班的周末) |
| | | work = HrmAttendanceHolidayTypeEnum.WORK_DAY.getType().equals(holidayType); |
| | | } else { |
| | | DayOfWeek dayOfWeek = current.getDayOfWeek(); |
| | | work = dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY; |
| | | } |
| | | if (work) { |
| | | workDays++; |
| | | } |
| | | current = current.plusDays(1); |
| | |
| | | return workDays; |
| | | } |
| | | |
| | | /** |
| | | * 节假日配置变更后,已有汇总的应出勤天数会与最新配置不一致。 |
| | | * 查询汇总时按最新节假日重算一次并回写,保证「应出勤天数」始终关联节假日配置。 |
| | | */ |
| | | private void refreshWorkDaysOfMonth(String yearMonth) { |
| | | if (StrUtil.isBlank(yearMonth)) { |
| | | return; |
| | | } |
| | | try { |
| | | YearMonth ym = YearMonth.parse(yearMonth); |
| | | attendanceSummaryMapper.updateWorkDaysByYearMonth(yearMonth, |
| | | calculateWorkDays(ym.atDay(1), ym.atEndOfMonth())); |
| | | } catch (Exception ex) { |
| | | // 刷新失败不影响查询本身,记录日志即可 |
| | | log.warn("[refreshWorkDaysOfMonth][yearMonth({}) 刷新应出勤天数失败]", yearMonth, ex); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<HrmAttendanceSummaryDO> getAttendanceSummaryPage(HrmAttendanceSummaryPageReqVO pageReqVO) { |
| | | // 查询前按最新节假日重算该月应出勤天数 |
| | | refreshWorkDaysOfMonth(pageReqVO.getYearMonth()); |
| | | return attendanceSummaryMapper.selectPage(pageReqVO, new LambdaQueryWrapperX<HrmAttendanceSummaryDO>() |
| | | .eqIfPresent(HrmAttendanceSummaryDO::getUserId, pageReqVO.getUserId()) |
| | | .eqIfPresent(HrmAttendanceSummaryDO::getDeptId, pageReqVO.getDeptId()) |
| | |
| | | |
| | | @Override |
| | | public List<HrmAttendanceSummaryDO> getDeptMonthlySummaryList(Long deptId, String yearMonth) { |
| | | // 查询前按最新节假日重算该月应出勤天数 |
| | | refreshWorkDaysOfMonth(yearMonth); |
| | | return attendanceSummaryMapper.selectListByDeptIdAndYearMonth(deptId, yearMonth); |
| | | } |
| | | |