package cn.iocoder.yudao.module.hrm.service.attendance;
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRulePageReqVO;
|
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRuleSaveReqVO;
|
import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceRuleDO;
|
import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmAttendanceRuleMapper;
|
import jakarta.annotation.Resource;
|
import org.springframework.stereotype.Service;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDate;
|
import java.util.List;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.*;
|
|
/**
|
* 考勤规则配置 Service 实现类
|
*
|
* 说明:同一部门允许配置多条规则,按「生效开始日期 / 生效结束日期」区间区分;
|
* 匹配时取覆盖目标日期、且生效开始日期最晚的那条(无日期的视为长期有效,优先级最低)。
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class HrmAttendanceRuleServiceImpl implements HrmAttendanceRuleService {
|
|
@Resource
|
private HrmAttendanceRuleMapper attendanceRuleMapper;
|
|
@Override
|
public Long createAttendanceRule(HrmAttendanceRuleSaveReqVO createReqVO) {
|
// 校验规则名称是否重复(同一部门允许多条规则,不再限制部门唯一)
|
validateAttendanceRuleNameUnique(null, createReqVO.getName());
|
validateEffectiveDateRange(createReqVO.getEffectiveStartDate(), createReqVO.getEffectiveEndDate());
|
HrmAttendanceRuleDO attendanceRule = BeanUtils.toBean(createReqVO, HrmAttendanceRuleDO.class);
|
// 设置默认值
|
if (attendanceRule.getLateAllowMinutes() == null) {
|
attendanceRule.setLateAllowMinutes(0);
|
}
|
if (attendanceRule.getEarlyAllowMinutes() == null) {
|
attendanceRule.setEarlyAllowMinutes(0);
|
}
|
if (attendanceRule.getOvertimeThreshold() == null) {
|
attendanceRule.setOvertimeThreshold(BigDecimal.ONE);
|
}
|
if (attendanceRule.getStatus() == null) {
|
attendanceRule.setStatus(0);
|
}
|
attendanceRuleMapper.insert(attendanceRule);
|
return attendanceRule.getId();
|
}
|
|
@Override
|
public void updateAttendanceRule(HrmAttendanceRuleSaveReqVO updateReqVO) {
|
validateAttendanceRuleExists(updateReqVO.getId());
|
// 校验规则名称是否重复
|
validateAttendanceRuleNameUnique(updateReqVO.getId(), updateReqVO.getName());
|
validateEffectiveDateRange(updateReqVO.getEffectiveStartDate(), updateReqVO.getEffectiveEndDate());
|
HrmAttendanceRuleDO updateObj = BeanUtils.toBean(updateReqVO, HrmAttendanceRuleDO.class);
|
attendanceRuleMapper.updateById(updateObj);
|
}
|
|
@Override
|
public void deleteAttendanceRule(Long id) {
|
validateAttendanceRuleExists(id);
|
attendanceRuleMapper.deleteById(id);
|
}
|
|
private void validateAttendanceRuleExists(Long id) {
|
if (attendanceRuleMapper.selectById(id) == null) {
|
throw exception(ATTENDANCE_RULE_NOT_EXISTS);
|
}
|
}
|
|
private void validateAttendanceRuleNameUnique(Long id, String name) {
|
HrmAttendanceRuleDO rule = attendanceRuleMapper.selectOne(HrmAttendanceRuleDO::getName, name);
|
if (rule == null) {
|
return;
|
}
|
if (id == null) {
|
throw exception(ATTENDANCE_RULE_NAME_EXISTS);
|
}
|
if (!rule.getId().equals(id)) {
|
throw exception(ATTENDANCE_RULE_NAME_EXISTS);
|
}
|
}
|
|
/**
|
* 校验生效日期区间:开始日期不能晚于结束日期
|
*/
|
private void validateEffectiveDateRange(LocalDate startDate, LocalDate endDate) {
|
if (startDate != null && endDate != null && startDate.isAfter(endDate)) {
|
throw exception(ATTENDANCE_RULE_EFFECTIVE_DATE_INVALID);
|
}
|
}
|
|
@Override
|
public HrmAttendanceRuleDO getAttendanceRule(Long id) {
|
return attendanceRuleMapper.selectById(id);
|
}
|
|
@Override
|
public PageResult<HrmAttendanceRuleDO> getAttendanceRulePage(HrmAttendanceRulePageReqVO pageReqVO) {
|
return attendanceRuleMapper.selectPage(pageReqVO);
|
}
|
|
@Override
|
public List<HrmAttendanceRuleDO> getAttendanceRuleList() {
|
return attendanceRuleMapper.selectListByStatus(0);
|
}
|
|
@Override
|
public HrmAttendanceRuleDO getAttendanceRuleByDeptId(Long deptId, LocalDate date) {
|
LocalDate targetDate = date != null ? date : LocalDate.now();
|
// 1. 先查找部门专属规则(覆盖目标日期的,生效开始日期最晚的优先)
|
if (deptId != null) {
|
List<HrmAttendanceRuleDO> deptRules = selectEffectiveRules(deptId, targetDate);
|
if (!deptRules.isEmpty()) {
|
return deptRules.get(0);
|
}
|
}
|
// 2. 查找全局规则(deptId 为 null)
|
List<HrmAttendanceRuleDO> globalRules = selectEffectiveRules(null, targetDate);
|
if (!globalRules.isEmpty()) {
|
return globalRules.get(0);
|
}
|
return null;
|
}
|
|
/**
|
* 查询在指定日期生效的规则
|
*
|
* @param deptId 部门ID,null 表示全局规则
|
* @param date 目标日期
|
*/
|
private List<HrmAttendanceRuleDO> selectEffectiveRules(Long deptId, LocalDate date) {
|
LambdaQueryWrapperX<HrmAttendanceRuleDO> wrapper = new LambdaQueryWrapperX<>();
|
if (deptId == null) {
|
wrapper.isNull(HrmAttendanceRuleDO::getDeptId);
|
} else {
|
wrapper.eq(HrmAttendanceRuleDO::getDeptId, deptId);
|
}
|
wrapper.eq(HrmAttendanceRuleDO::getStatus, 0);
|
// 生效开始日期为空(不限)或 <= 目标日期
|
wrapper.and(w -> w.isNull(HrmAttendanceRuleDO::getEffectiveStartDate)
|
.or().le(HrmAttendanceRuleDO::getEffectiveStartDate, date));
|
// 生效结束日期为空(不限)或 >= 目标日期
|
wrapper.and(w -> w.isNull(HrmAttendanceRuleDO::getEffectiveEndDate)
|
.or().ge(HrmAttendanceRuleDO::getEffectiveEndDate, date));
|
// 生效开始日期越晚优先级越高;同开始日期时取先创建的
|
wrapper.orderByDesc(HrmAttendanceRuleDO::getEffectiveStartDate);
|
wrapper.orderByAsc(HrmAttendanceRuleDO::getId);
|
return attendanceRuleMapper.selectList(wrapper);
|
}
|
|
}
|