假期管理

This commit is contained in:
aikai 2024-11-11 09:11:17 +08:00
parent 8aa1ce4a1e
commit 26c490a260
46 changed files with 314 additions and 110 deletions

View File

@ -62,6 +62,10 @@ public class Constants {
* yyyy-MM-dd格式
*/
public static final DateTimeFormatter REPO_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
/**
* yyyy-MM
*/
public static final DateTimeFormatter YEAR_MONTH_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM");
/**
* yyyy-MM-dd HH:mm:ss格式
*/

View File

@ -155,6 +155,7 @@ public class LocalDateTimeUtils {
*/
public static List<LocalDateTime> getTheDayOfEachMonthSoFar(LocalDateTime beginTime, LocalDateTime endTime, int day) {
List<LocalDateTime> monthlyFirstDays = new ArrayList<>();
beginTime = beginTime.withDayOfMonth(day);
while (!beginTime.isAfter(endTime)) {
// 获取当月的1号
LocalDateTime firstDayOfMonth = beginTime.withDayOfMonth(day);

View File

@ -29,6 +29,9 @@ public interface ErrorCodeConstants {
ErrorCode NO_NEED_TO_APPLY_FOR_OVERTIME_IF_NOT_IN_THE_ATTENDANCE_GROUP = new ErrorCode(1_009_001_014, "不在考勤组内无需申请加班");
ErrorCode EXCEPTION_OCCURRED_WHILE_OBTAINING_OVERTIME_SETTINGS = new ErrorCode(1_009_001_015, "获取加班设置出现异常");
ErrorCode ABNORMAL_ACCESS_TO_ATTENDANCE_RECORDS = new ErrorCode(1_009_001_016, "获取考勤记录异常");
ErrorCode OVERTIME_REQUESTS_ALREADY_EXIST_FOR_THE_SAME_TIME_PERIOD = new ErrorCode(1_009_001_018, "已存在相同时间段的加班申请");
ErrorCode THE_CURRENT_USERS_ATTENDANCE_GROUP_HAS_NOT_SET_OVERTIME_RULES = new ErrorCode(1_009_001_019, "当前用户所在考勤组未设置加班规则");
ErrorCode OA_REIMBURSEMENT_NOT_EXISTS = new ErrorCode(1_009_001_100, "报销申请不存在");
ErrorCode OA_EVECTION_NOT_EXISTS = new ErrorCode(1_009_001_101, "出差申请不存在");
ErrorCode OA_SEAL_NOT_EXISTS = new ErrorCode(1_009_001_102, "用章申请不存在");

View File

@ -40,7 +40,7 @@ public class BpmOAOvertimeController {
private BpmOAOvertimeItemService overtimeItemService;
@PostMapping("/create")
@Operation(summary = "创建请求申请")
@Operation(summary = "创建加班申请")
public CommonResult<Long> createOvertime(@Valid @RequestBody BpmOAOvertimeCreateReqVO createReqVO) {
return success(overtimeService.createOvertime(getLoginUserId(), createReqVO));
@ -54,7 +54,7 @@ public class BpmOAOvertimeController {
List<BpmOAOvertimeItemDO> itemDOS = overtimeItemService.getByOvertimeId(id);
List<BpmOAOvertimeItemVO> overtimeDateTimeVOS = BeanUtil.copyToList(itemDOS, BpmOAOvertimeItemVO.class);
BpmOAOvertimeRespVO vo = BpmOAOvertimeConvert.INSTANCE.convert(overtime);
return success(vo.setOvertimeDateTimeVOS(overtimeDateTimeVOS));
return success(vo.setTotalTimeLength(overtime.getTimeLength()).setOvertimeDateTimeVOS(overtimeDateTimeVOS));
}
@GetMapping("/getByProcessInstanceId")
@ -65,6 +65,6 @@ public class BpmOAOvertimeController {
List<BpmOAOvertimeItemDO> itemDOS = overtimeItemService.getByOvertimeId(overtime.getId());
List<BpmOAOvertimeItemVO> overtimeDateTimeVOS = BeanUtil.copyToList(itemDOS, BpmOAOvertimeItemVO.class);
BpmOAOvertimeRespVO vo = BpmOAOvertimeConvert.INSTANCE.convert(overtime);
return success(vo.setOvertimeDateTimeVOS(overtimeDateTimeVOS));
return success(vo.setTotalTimeLength(overtime.getTimeLength()).setOvertimeDateTimeVOS(overtimeDateTimeVOS));
}
}

View File

@ -1,11 +1,14 @@
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.overtime;
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@ -21,8 +24,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
*/
@Schema(description = "管理后台 - 加班申请创建 Request VO")
@Data
@EqualsAndHashCode()
@ToString(callSuper = true)
public class BpmOAOvertimeCreateReqVO {
@Schema(description = "加班原因", requiredMode = Schema.RequiredMode.REQUIRED)
@ -31,12 +32,10 @@ public class BpmOAOvertimeCreateReqVO {
@Schema(description = "加班的开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime startTime;
@Schema(description = "加班的结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime endTime;
@Schema(description = "加班日期时间列表", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -147,6 +147,8 @@ public class BpmOAEntryServiceImpl implements BpmOAEntryService {
.setUrls(convertList(uploadUserFiles, UploadUserFile::getUrl))
.setUserId(userId);
fileApi.updateUserFileUserId(updateReqDTO);
// 更新用户入职时间到users表中
userApi.updateUserEntryDate(new UserSaveRespDTO().setId(userId).setEntryDate(entry.getEntryDate().atStartOfDay()));
}
}

View File

@ -79,13 +79,6 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav
@Override
@Transactional(rollbackFor = Exception.class)
public Long createLeave(Long userId, BpmOALeaveCreateReqVO createReqVO) {
List<Integer> processingOrPassed = BpmProcessInstanceResultEnum.processingOrPassed();
List<BpmOALeaveDO> bpmOALeaveDOS = leaveMapper.selectList(new LambdaQueryWrapper<BpmOALeaveDO>()
.eq(BpmOALeaveDO::getUserId, userId)
.le(BpmOALeaveDO::getStartTime, createReqVO.getEndTime())
.gt(BpmOALeaveDO::getEndTime, createReqVO.getStartTime())
.in(BpmOALeaveDO::getResult, processingOrPassed)
);
BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convert(createReqVO)
.setUserId(userId)
.setFileItems(createReqVO.getFileItems())
@ -93,6 +86,13 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav
// 构建请假开始 or 结束时间
LocalDateTime[] times = this.builderLeaveTime(leave);
List<Integer> processingOrPassed = BpmProcessInstanceResultEnum.processingOrPassed();
List<BpmOALeaveDO> bpmOALeaveDOS = leaveMapper.selectList(new LambdaQueryWrapper<BpmOALeaveDO>()
.eq(BpmOALeaveDO::getUserId, userId)
.le(BpmOALeaveDO::getStartTime, leave.getEndTime())
.gt(BpmOALeaveDO::getEndTime, leave.getStartTime())
.in(BpmOALeaveDO::getResult, processingOrPassed)
);
// -- 判断是否有重复时间
if (CollectionUtil.isNotEmpty(bpmOALeaveDOS)) {
for (BpmOALeaveDO bpmOALeaveDO : bpmOALeaveDOS) {
@ -110,7 +110,7 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav
// 发起 BPM 流程
Map<String, Object> processInstanceVariables = new HashMap<>();
processInstanceVariables.put("duration", leave.getDuration());
// processInstanceVariables.put("duration", leave.getDuration().toString());
String processInstanceId = processInstanceApi.createProcessInstance(userId,
new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(leave.getId()))).getCheckedData();

View File

@ -2,11 +2,15 @@ package cn.iocoder.yudao.module.bpm.service.oa;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.overtime.BpmOAOvertimeCreateReqVO;
@ -31,6 +35,7 @@ import cn.iocoder.yudao.module.system.api.holiday.dto.OvertimeIncreasesHolidayDT
import cn.iocoder.yudao.module.system.api.workovertime.WorkOvertimeApi;
import cn.iocoder.yudao.module.system.api.workovertime.vo.WorkOvertimeRuleApiVO;
import cn.iocoder.yudao.module.system.api.workovertime.vo.WorkOvertimeRuleItemApiVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -39,6 +44,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -86,39 +92,62 @@ public class BpmOAOvertimeServiceImpl extends BpmOABaseService implements BpmOAO
@Override
@Transactional(rollbackFor = Exception.class)
public Long createOvertime(Long userId, BpmOAOvertimeCreateReqVO vo) {
// TODO: 2024/10/29 这里还需要判断是否已存在相同时间段的加班申请
// 判断是否已存在相同时间段的加班申请
List<String> dataTimes = DateUtils.betweenDayList(vo.getStartTime(), vo.getEndTime());
List<Integer> processingOrPassed = BpmProcessInstanceResultEnum.processingOrPassed();
// -- 减去一分钟的时间 - 由于前端可能是一天中的最开始时间 - 这里要处理下
LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(vo.getStartTime());
LocalDateTime endTime = LocalDateTimeUtil.endOfDay(vo.getEndTime().plusMinutes(-1));
List<BpmOAOvertimeDO> overtimeDOS = overtimeMapper.selectList(new LambdaQueryWrapper<BpmOAOvertimeDO>()
.eq(BpmOAOvertimeDO::getUserId, userId)
.le(BpmOAOvertimeDO::getStartTime, endTime)
.gt(BpmOAOvertimeDO::getEndTime, beginTime)
.in(BpmOAOvertimeDO::getResult, processingOrPassed)
);
LocalDateTime[] times = new LocalDateTime[]{beginTime, endTime};
if (CollectionUtil.isNotEmpty(overtimeDOS)) {
for (BpmOAOvertimeDO overtimeDO : overtimeDOS) {
LocalDateTime[] itemTimes = new LocalDateTime[]{overtimeDO.getStartTime(), overtimeDO.getEndTime()};
boolean intersects = LocalDateTimeUtils.intersects(times[0], times[1], itemTimes[0], itemTimes[1]);
if (intersects) {
throw exception(OVERTIME_REQUESTS_ALREADY_EXIST_FOR_THE_SAME_TIME_PERIOD);
}
}
}
CommonResult<WorkOvertimeRuleApiVO> resultData = workOvertimeApi.getOvertimeRulesByUserId(userId);
// -- 获取用户考勤信息
if (!resultData.isSuccess()) {
throw exception(EXCEPTION_OCCURRED_WHILE_OBTAINING_OVERTIME_SETTINGS);
}
// -- 不在考勤组内不需要加班
WorkOvertimeRuleApiVO workOvertimeRuleApiVO = resultData.getCheckedData();
if (Constants.ZERO.equals(workOvertimeRuleApiVO.getIsGroup())) {
throw exception(NO_NEED_TO_APPLY_FOR_OVERTIME_IF_NOT_IN_THE_ATTENDANCE_GROUP);
}
if (Constants.ZERO.equals(workOvertimeRuleApiVO.getIsOvertime())) {
throw exception(THE_CURRENT_USERS_ATTENDANCE_GROUP_HAS_NOT_SET_OVERTIME_RULES);
}
List<WorkOvertimeRuleItemApiVO> workOvertimeRuleItems = workOvertimeRuleApiVO.getWorkOvertimeRuleItems();
Map<Integer, WorkOvertimeRuleItemApiVO> map = workOvertimeRuleItems.stream().collect(Collectors.toMap(WorkOvertimeRuleItemApiVO::getType, Function.identity()));
// 根据时间计算是工作日还是节假日还是休息日
Map<String, AttendanceTimeRangeInfoVO> attendanceInfoByTimeRange = leaveService.getAttendanceInfoByTimeRange(
new AttendanceTimeRangeInfoDTO().setUserId(userId).setStartTime(vo.getStartTime()).setEndTime(vo.getEndTime())
);
for (String dataTime : dataTimes) {
AttendanceTimeRangeInfoVO attendanceTimeRangeInfoVO = attendanceInfoByTimeRange.get(dataTime);
WorkOvertimeRuleItemApiVO workOvertimeRuleItemApiVO = map.get(attendanceTimeRangeInfoVO.getDatType());
if (workOvertimeRuleItemApiVO.getStatus() == 0) {
String msg = "%s不允许加班";
msg = String.format(msg, (dataTime + "" + (attendanceTimeRangeInfoVO.getDatType() == 1 ? "工作日" : attendanceTimeRangeInfoVO.getDatType() == 2 ? "休息日" : "节假日")));
throw exception(new ErrorCode(1_009_001_016, msg));
throw exception(new ErrorCode(1_009_001_017, msg));
}
}
// 判断不在考勤组内 不需要加班
AttendanceTimeRangeInfoVO attendanceTimeRangeInfoVO = attendanceInfoByTimeRange.get(dataTimes.get(0));
if (attendanceTimeRangeInfoVO == null || Constants.FALSE.equals(attendanceTimeRangeInfoVO.getInGroup())) {
throw exception(NO_NEED_TO_APPLY_FOR_OVERTIME_IF_NOT_IN_THE_ATTENDANCE_GROUP);
}
//插入OA 加班申请
BpmOAOvertimeDO overtime = BpmOAOvertimeConvert.INSTANCE.convert(vo).setUserId(userId)
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
overtimeMapper.insert(overtime);
overtimeMapper.insert(overtime.setTimeLength(vo.getTotalTimeLength()));
// -- 记录一个item表
List<BpmOAOvertimeItemDO> itemDOS = BeanUtil.copyToList(vo.getOvertimeDateTimeVOS(), BpmOAOvertimeItemDO.class);
@ -147,8 +176,6 @@ public class BpmOAOvertimeServiceImpl extends BpmOABaseService implements BpmOAO
return overtime.getId();
}
// TODO: 2024/10/29 加班申请通过 并且加班时间已过的
@Override
@Transactional(rollbackFor = Exception.class)
public void updateOvertimeResult(String processInstanceId, Long id, Integer result) {
@ -180,7 +207,14 @@ public class BpmOAOvertimeServiceImpl extends BpmOABaseService implements BpmOAO
if (!resultData.isSuccess()) {
throw exception(EXCEPTION_OCCURRED_WHILE_OBTAINING_OVERTIME_SETTINGS);
}
// -- 不在考勤组内不需要加班
WorkOvertimeRuleApiVO workOvertimeRuleApiVO = resultData.getCheckedData();
if (Constants.ZERO.equals(workOvertimeRuleApiVO.getIsGroup())) {
throw exception(NO_NEED_TO_APPLY_FOR_OVERTIME_IF_NOT_IN_THE_ATTENDANCE_GROUP);
}
if (Constants.ZERO.equals(workOvertimeRuleApiVO.getIsOvertime())) {
throw exception(THE_CURRENT_USERS_ATTENDANCE_GROUP_HAS_NOT_SET_OVERTIME_RULES);
}
List<WorkOvertimeRuleItemApiVO> workOvertimeRuleItems = workOvertimeRuleApiVO.getWorkOvertimeRuleItems();
Map<Integer, WorkOvertimeRuleItemApiVO> map = workOvertimeRuleItems.stream().collect(Collectors.toMap(WorkOvertimeRuleItemApiVO::getType, Function.identity()));
// --- 用户加班时间期间的打卡记录
@ -199,12 +233,15 @@ public class BpmOAOvertimeServiceImpl extends BpmOABaseService implements BpmOAO
WorkOvertimeRuleItemApiVO ruleItem = map.get(item.getDateType());
WorkOvertimeService resource = workOvertimeHandler.getResource(WorkOvertimeEnum.getEnumServerName(ruleItem.getType()));
List<AttendancePunchRecordVO> recordList = recordMap.get(item.getDateTimeStr());
if (recordList == null) {
recordList = new ArrayList<>();
}
recordList.sort(Comparator.comparing(AttendancePunchRecordVO::getShouldPunchTime));
// -- 计算加班时长
resource.getOvertimeHours(item, recordList, workOvertimeRuleApiVO, ruleItem);
editItems.add(item);
if (ruleItem.getTransformationType() == 1) {
// -- 如果是记为调休 - 并且假期id不为空
if (ruleItem.getTransformationType() == 1 && ruleItem.getHolidayId() != null) {
// -- 计算调休
if (item.getActualTimeLength().compareTo(BigDecimal.ZERO) > 0) {
// -- 计算每个调休对象需要进行的调休时长 - 这里的单位是小时 - 还要获取假期的单位 来转换一下

View File

@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAOvertimeItemDO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendancePunchRecordVO;
import cn.iocoder.yudao.module.system.api.workovertime.vo.WorkOvertimeDeductRuleApiVO;
import cn.iocoder.yudao.module.system.api.workovertime.vo.WorkOvertimeRuleApiVO;
import cn.iocoder.yudao.module.system.api.workovertime.vo.WorkOvertimeRuleItemApiVO;
import org.springframework.stereotype.Service;
@ -12,7 +11,6 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.temporal.ChronoUnit;
import java.util.List;
@ -37,10 +35,10 @@ public class WorkOvertimeRestDayServiceImpl implements WorkOvertimeRestDayServic
}
// --------------------- 在审批的时段内按打卡时长计算 3无需审批按打卡时长计算 ---------------------
BigDecimal overtimeHours = BigDecimal.ZERO;
// -- 节假 - 打了多久的卡就算多久 - 这里是计算加班时长 -
// -- 休息 - 打了多久的卡就算多久 - 这里是计算加班时长 -
AttendancePunchRecordVO first = CollUtil.getFirst(recordList);
AttendancePunchRecordVO last = CollUtil.getLast(recordList);
if (first.getPunchTime() == null || last.getPunchTime() == null) {
if (first == null || first.getPunchTime() == null || last == null || last.getPunchTime() == null) {
item.setActualTimeLength(overtimeHours);
return;
}

View File

@ -15,9 +15,11 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 加班 工作日
@ -47,10 +49,11 @@ public class WorkOvertimeWeekDayServiceImpl implements WorkOvertimeWeekDayServic
// 合并 AttendancePunchRecordVO列表中 UpWorkOvertimeTime 的和
Long upWorkOvertimeTime = recordList.stream().filter(a ->
//获取正常打卡的上班卡
a.getStatus().equals(0) && a.getWorkType().equals(1)
a.getStatus().equals(0) && a.getWorkType().equals(0)
// 计算班前多少分钟 小于n分钟 则不考虑
&& a.getUpWorkOvertimeTime() > 0 && TimeUnit.MILLISECONDS.toMinutes(a.getUpWorkOvertimeTime()) > ruleItem.getBeforeWorkOvertime())
.map(AttendancePunchRecordVO::getUpWorkOvertimeTime)
// TODO: 2024/11/9 这行计算有问题
.reduce(0L, Long::sum);
// -- 转换为分钟
long millis = TimeUnit.MILLISECONDS.toMinutes(upWorkOvertimeTime);
@ -82,6 +85,15 @@ public class WorkOvertimeWeekDayServiceImpl implements WorkOvertimeWeekDayServic
}
public static void main(String[] args) {
// 合并 AttendancePunchRecordVO列表中 UpWorkOvertimeTime 的和
List<AttendancePunchRecordVO> recordList = new ArrayList<>();
List<Long> collect = recordList.stream().filter(a ->
//获取正常打卡的上班卡
TimeUnit.MILLISECONDS.toMinutes(23114096L) > 30)
.map(AttendancePunchRecordVO::getUpWorkOvertimeTime).collect(Collectors.toList());
System.out.println(collect );
System.out.println(collect );
LocalDateTime localDateTime = LocalDateTime.of(2024, 6, 25, 17, 30, 0);
LocalDateTime plus = localDateTime.plus(1931472, ChronoUnit.MILLIS);
long between = LocalDateTimeUtil.between(localDateTime, plus, ChronoUnit.MINUTES);

View File

@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.system.api.attendance.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.List;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* @author 艾楷
*/
@ -20,11 +23,13 @@ public class AttendanceTimeRangeInfoDTO {
* 开始时间
*/
@Schema(description = "开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime startTime;
/**
* 结束时间
*/
@Schema(description = "结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime endTime;
/**

View File

@ -27,5 +27,5 @@ public class OvertimeIncreasesHolidayDTO {
private Integer unit;
@Schema(description = "日折算时长 n小时 = 一天 ")
private Integer conversion;
private BigDecimal conversion;
}

View File

@ -82,14 +82,14 @@ public interface AdminUserApi {
@Parameter(name = "userId", description = "用户id", example = "1024", required = true)
@Parameter(name = "fieldworkFlag", description = "是否可外勤打卡 | 0否 1是", example = "1", required = true)
void updateFieldworkType(@RequestParam("userId") Long userId,
@RequestParam("fieldworkFlag") Integer fieldworkFlag);
@RequestParam("fieldworkFlag") Integer fieldworkFlag);
@PostMapping(PREFIX + "/updateUserStaffing")
@Operation(summary = "修改用户信息")
@Parameter(name = "userId", description = "用户id", example = "1024", required = true)
@Parameter(name = "userStaffing", description = "用户编制", example = "1", required = true)
void updateUserStaffing(@RequestParam("userId") Long userId,
@RequestParam("userStaffing") Integer userStaffing);
@RequestParam("userStaffing") Integer userStaffing);
@GetMapping(PREFIX + "/getUserIdsByUserNature")
@Operation(summary = "获取所有用户性质为外勤的用户")
@ -101,4 +101,7 @@ public interface AdminUserApi {
@Parameter(name = "factoryId", description = "工厂id", example = "1024", required = false)
CommonResult<List<AdminUserRpcVO>> getFactoryUsers(@RequestParam(name = "factoryId", required = false) Long factoryId);
@PostMapping(PREFIX + "/updateUserEntryDate")
@Operation(summary = "更新用户入职信息")
CommonResult updateUserEntryDate(@RequestBody UserSaveRespDTO userSaveRespDTO);
}

View File

@ -26,7 +26,7 @@ public class WorkOvertimeMoreRuleApiVO {
private BigDecimal roundingIncrementalValue;
@Schema(description = "日折算时长 n小时 = 一天 ")
private Integer conversion;
private BigDecimal conversion;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;

View File

@ -30,4 +30,10 @@ public class WorkOvertimeRuleApiVO {
@Schema(description = "更多规则")
private WorkOvertimeMoreRuleApiVO moreRule;
@Schema(description = "是否在考勤组内 0否 1是")
private Integer isGroup = 1;
@Schema(description = "是否有加班规则 0否 1是")
private Integer isOvertime = 1;
}

View File

@ -115,4 +115,10 @@ public class AdminUserApiImpl implements AdminUserApi {
return success(BeanUtils.toBean(factoryUsers, AdminUserRpcVO.class));
}
@Override
public CommonResult updateUserEntryDate(UserSaveRespDTO dto) {
userService.updateUserEntryDate(dto.getId(), dto.getEntryDate());
return success(true);
}
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.api.workovertime;
import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.workovertime.vo.WorkOvertimeRuleApiVO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO;
@ -26,7 +27,13 @@ public class WorkOvertimeApiImpl implements WorkOvertimeApi {
WorkOvertimeRuleApiVO vo = new WorkOvertimeRuleApiVO();
//先获取当前用户所在考勤组 - 再根据考勤组 查询对应的加班规则
AttendanceGroupDO attendanceGroupDO = attendanceGroupService.getByUserId(userId);
if (attendanceGroupDO == null) {
return CommonResult.success(vo.setIsGroup(Constants.ZERO));
}
WorkOvertimeRuleDO workOvertimeRuleDO = workOvertimeRuleAttendanceGroupService.getRuleByAttendanceGroupId(attendanceGroupDO.getId());
if (workOvertimeRuleDO == null){
return CommonResult.success(vo.setIsOvertime(Constants.ZERO));
}
BeanUtil.copyProperties(workOvertimeRuleDO, vo);
return CommonResult.success(vo);
}

View File

@ -9,6 +9,7 @@ import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
@Data
@ -28,6 +29,8 @@ public class AttendancePunchPageVO {
private Integer punchType = 4;
@Schema(description = "当天考勤列表")
private List<AttendanceOnTheDayDTO> attendanceOnTheDayDTOS;
@Schema(description = "是否加班 0否 1是")
private Integer workOvertimeFlag = 0;
/**
* redisKey
@ -71,4 +74,16 @@ public class AttendancePunchPageVO {
* 当前用户
*/
private AdminUserDO user;
/**
* 处理加班打卡 不计算是否迟到早退
* @param punchType
*/
public void setPunchType(Integer punchType) {
if (this.getFieldworkFlag() == 0) {
this.punchType = punchType;
} else {
this.punchType = Arrays.asList(0, 2).contains(punchType) ? 0 : 1;
}
}
}

View File

@ -93,6 +93,13 @@ public class AttendanceGroupController {
return success(BeanUtils.toBean(pageResult, AttendanceGroupRespVO.class));
}
@GetMapping("/getAllFilterWorkOvertimeRule")
@Operation(summary = "获得所有考勤组过滤已绑定过加班规则的")
public CommonResult<List<AttendanceGroupRespVO>> getAllFilterWorkOvertimeRule(@RequestParam(required = false) Long workOvertimeRuleId) {
List<AttendanceGroupDO> pageResult = groupService.getAllFilterWorkOvertimeRule(workOvertimeRuleId);
return success(BeanUtils.toBean(pageResult, AttendanceGroupRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出考勤组 Excel")
@PreAuthorize("@ss.hasPermission('attendance:group:export')")

View File

@ -25,6 +25,9 @@ public class AttendanceGroupPageReqVO extends PageParam {
@Schema(description = "群组名称", example = "李四")
private String groupName;
@Schema(description = "考勤人员名称", example = "李四")
private String userNickname;
@Schema(description = "考勤类型 1固定班制 2排班制", example = "1")
private Integer type;

View File

@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.annotation.security.PermitAll;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;

View File

@ -62,6 +62,9 @@ public class AttendancePunchRecordSaveReqVO {
@Schema(description = "打卡时间")
private LocalDateTime punchTime;
@Schema(description = "日期yyyy-MM-dd格式 (实际是哪一天)")
private String actualDayTime;
@Schema(description = "打卡备注", example = "你说的对")
private String remark;

View File

@ -42,4 +42,7 @@ public class UserPageReqVO extends PageParam {
@Schema(description = "部门ids", example = "1024")
private List<Long> deptIds;
@Schema(description = "考勤组ids", example = "1024")
private List<Long> groupIds;
}

View File

@ -29,7 +29,7 @@ public class WorkOvertimeMoreRulePageReqVO extends PageParam {
private BigDecimal roundingIncrementalValue;
@Schema(description = "日折算时长 n小时 = 一天 ")
private Integer conversion;
private BigDecimal conversion;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)

View File

@ -36,7 +36,7 @@ public class WorkOvertimeMoreRuleRespVO {
@Schema(description = "日折算时长 n小时 = 一天 ")
@ExcelProperty("日折算时长 n小时 = 一天 ")
private Integer conversion;
private BigDecimal conversion;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")

View File

@ -27,7 +27,7 @@ public class WorkOvertimeMoreRuleSaveReqVO {
private BigDecimal roundingIncrementalValue;
@Schema(description = "日折算时长 n小时 = 一天 ")
private Integer conversion;
private BigDecimal conversion;
@Schema(description = "更多规则拓展列表")
private List<WorkOvertimeMoreRuleExtSaveReqVO> moreRuleExtList;

View File

@ -15,11 +15,10 @@ public interface HolidayRemindConvert {
/**
* @param openId 微信小程序唯一id
* @param nickname 发布人姓名
* @param miniProgramState 小程序的状态
* @return
*/
default SubscribeMessageReqDTO convertHolidayRemind(String openId, String comment, String nickname, String miniProgramState) {
default SubscribeMessageReqDTO convertHolidayRemind(String openId, String comment, String miniProgramState) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(openId);
message.setTemplateId("fH29xjNb8pe-7onQ-wE3QrBAC-y8aaC_oosYZKNMtzM");
@ -27,14 +26,14 @@ public interface HolidayRemindConvert {
//消息类型
MsgData noticeType = new MsgData();
noticeType.setName("phrase8");
noticeType.setValue("评论回复");
noticeType.setValue("假期提醒");
message.addData(noticeType);
//发送人
MsgData publishMan = new MsgData();
publishMan.setName("thing16");
publishMan.setValue(nickname);
publishMan.setValue("系统提醒");
message.addData(publishMan);
//发送时间

View File

@ -49,7 +49,7 @@ public class WorkOvertimeMoreRuleDO extends BaseDO {
/**
* 日折算时长 n小时 = 一天
*/
private Integer conversion;
private BigDecimal conversion;
/**
* 更多规则拓展列表

View File

@ -49,4 +49,11 @@ public interface AttendanceGroupMapper extends BaseMapperX<AttendanceGroupDO> {
* @return
*/
IPage<AttendanceGroupDO> selectPageList(@Param("vo") AttendanceGroupPageReqVO vo, @Param("page") Page page);
/**
* 获取所有考勤组过滤绑定过加班规则的
*
* @return
*/
List<AttendanceGroupDO> getAllFilterWorkOvertimeRule(@Param("workOvertimeRuleId") Long workOvertimeRuleId);
}

View File

@ -29,8 +29,6 @@ import java.util.stream.Collectors;
@Slf4j
public class HolidayGrantJob {
// TODO: 2024/4/22 - 每十分钟执行一次 将漏打卡的设为缺卡 这里的update要保证命中索引 保证是行锁 不然容易导致锁表
@Resource
private HolidayBalanceSettingService holidayBalanceSettingService;
@Resource
@ -74,7 +72,7 @@ public class HolidayGrantJob {
&& holidayBalanceSettingDO.getIssueTime() != null
&& holidayBalanceSettingDO.getIssueTime().isBefore(now)).collect(Collectors.toList());
if (CollectionUtil.isEmpty(fixedGrantList)) {
if (CollectionUtil.isNotEmpty(fixedGrantList)) {
for (HolidayBalanceSettingDO holidayBalanceSettingDO : fixedGrantList) {
// 计算下一次发放日期
LocalDateTime issueTime = holidaySettingService.calculateNextReleaseDate(now, holidayBalanceSettingDO);
@ -87,25 +85,6 @@ public class HolidayGrantJob {
holidayBalanceSettingService.batchUpdate(editList);
}
// TODO: 2024/10/23 这里要怎么去判断按照用户入职时间的话 是否发放过
// -- 过滤出按照员工入职时间发放的
// List<HolidayBalanceSettingDO> employmentGrantList = list.stream().filter(holidayBalanceSettingDO ->
// holidayBalanceSettingDO.getType() == 2 && holidayBalanceSettingDO.getIssueTimeType() == 1)
// .collect(Collectors.toList());
// // -- 获取到这些后 - 再获取到用户
// if (CollectionUtil.isNotEmpty(employmentGrantList)) {
// for (HolidayBalanceSettingDO holidayBalanceSettingDO : employmentGrantList) {
// Long holidaySettingId = holidayBalanceSettingDO.getHolidaySettingId();
// List<HolidaySettingRangeDO> rangeList = holidaySettingRangeMap.get(holidaySettingId);
// List<AdminUserDO> usersByRange = holidaySettingRangeService.getUsersByRange(rangeList);
// // 搞个表记录下按照员工入职时间发放的
// List<AdminUserDO> users = usersByRange.stream().filter(a -> a.getEntryDate() != null && a.getEntryDate().isBefore(now)).collect(Collectors.toList());
// if (CollectionUtil.isNotEmpty(users)) {
// holidayUserRecordService.grant(holidaySettingMap.get(holidaySettingId), holidaySettingRangeMap.get(holidaySettingId), holidayBalanceSettingDO, holidayWorkingAgeDOMap.get(holidaySettingId));
// }
// }
// }
log.info("结束 发放假期");
// 返回执行成功
return ReturnT.SUCCESS;

View File

@ -30,8 +30,6 @@ import java.util.stream.Collectors;
@Slf4j
public class HolidayRemindJob {
// TODO: 2024/4/22 - 每十分钟执行一次 将漏打卡的设为缺卡 这里的update要保证命中索引 保证是行锁 不然容易导致锁表
@Resource
private HolidayBalanceSettingService holidayBalanceSettingService;
@Resource
@ -115,6 +113,9 @@ public class HolidayRemindJob {
// 获取到主管 - 这里获取主管需要查询到对应用户所在的部门 - 完了后 在获取部门中的userIds
AdminUserDO adminUserDO = leaderMap.get(user.getDeptId());
remindDTO.setUserId(adminUserDO.getId());
if (leaderMap.get(adminUserDO.getId()) == null || leaderMap.get(adminUserDO.getId()).getOpenId() == null) {
continue;
}
remindDTO.setOpenId(leaderMap.get(adminUserDO.getId()).getOpenId());
remindDTO.setMsg(user.getNickname() + "" + name + "假期即将过期");
holidayRemindDTOS.add(remindDTO);
@ -127,9 +128,11 @@ public class HolidayRemindJob {
// 获取到主管 - 这里获取主管需要查询到对应用户所在的部门 - 完了后 在获取部门中的userIds
AdminUserDO adminUserDO = leaderMap.get(user.getDeptId());
remindDTO.setUserId(adminUserDO.getId());
remindDTO.setOpenId(leaderMap.get(adminUserDO.getId()).getOpenId());
remindDTO.setMsg(user.getNickname() + "" + name + "假期即将过期");
holidayRemindDTOS.add(remindDTO);
if (leaderMap.get(adminUserDO.getId()) != null && leaderMap.get(adminUserDO.getId()).getOpenId() == null) {
remindDTO.setOpenId(leaderMap.get(adminUserDO.getId()).getOpenId());
remindDTO.setMsg(user.getNickname() + "" + name + "假期即将过期");
holidayRemindDTOS.add(remindDTO);
}
}
}
}
@ -138,7 +141,7 @@ public class HolidayRemindJob {
for (HolidayRemindDTO holidayRemindDTO : holidayRemindDTOS) {
try {
subscribeMessageSendApi.sendWorkLogComment(HolidayRemindConvert.INSTANCE.convertHolidayRemind(
holidayRemindDTO.getOpenId(), holidayRemindDTO.getMsg(), userMap.get(holidayRemindDTO.getUserId()).getNickname(),
holidayRemindDTO.getOpenId(), holidayRemindDTO.getMsg(),
"formal"));
} catch (Exception e) {
log.error("发送假期过期提醒失败:{}", holidayRemindDTO);

View File

@ -220,11 +220,12 @@ public class AttendanceServiceImpl implements AttendanceService {
.setDayTime(pageVO.getTargetDayStr())
.setShouldPunchTime(pageVO.getShouldPunchTime())
.setPunchTime(dto.getLocalDateTime())
.setActualDayTime(pageVO.getTargetDayStr())
//取绝对值 如果status是负数则变为正数
.setLateTime(Constants.ONE.equals(status) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L)
.setLeaveEarlyTime(Constants.TWO.equals(status) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L)
.setDownWorkOvertimeTime(Constants.ZERO.equals(status) && Constants.ONE.equals(pageVO.getPunchType()) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L)
.setUpWorkOvertimeTime(Constants.ZERO.equals(status) && Constants.ZERO.equals(pageVO.getPunchType()) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L)
.setDownWorkOvertimeTime(Constants.ZERO.equals(status) && Constants.ONE.equals(pageVO.getPunchType()) && Constants.ZERO.equals(pageVO.getWorkOvertimeFlag()) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L)
.setUpWorkOvertimeTime(Constants.ZERO.equals(status) && Constants.ZERO.equals(pageVO.getPunchType()) && Constants.ZERO.equals(pageVO.getWorkOvertimeFlag()) ? Math.abs(LocalDateTimeUtil.between(dto.getLocalDateTime(), pageVO.getShouldPunchTime(), ChronoUnit.MILLIS)) : 0L)
.setRemark(dto.getRemark())
.setImage(dto.getImage())
.setPunchAddress(dto.getPunchAddress());
@ -363,7 +364,6 @@ public class AttendanceServiceImpl implements AttendanceService {
break;
} else {
// 如果是未打卡 - 判断当前时间是否在打卡区间内 - 如果不在的话直接set缺卡
// - 定时任务还没来得及刷新redis 数据 - 这里需要手动刷新
updateRedis = true;
attendanceOnTheDayDTO.setPunchStatus(AttendanceOnTheDayDTO.PUNCH_STATUS_MISS);
}

View File

@ -232,16 +232,24 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch
// -- 判断是否根据节假日自动排班 - 如果是的话 - 根据排班的来
Boolean isHolidayFlag = Constants.TRUE.equals(activationGroup.getAutoHolidaysFlag()) ?
attendanceService.isHoliday(dto.getLocalDateTime()) : null;
// -- 当前是节假日 并且是放假
if (isHolidayFlag != null && isHolidayFlag) {
return vo.setTodayNeedAttendance(Constants.FALSE);
}
//获取到当天是周几 - 如果是节假日补班的话 - 班次日期就是8
int week = isHolidayFlag != null ? 8 : dto.getLocalDateTime().getDayOfWeek().getValue();
// -- 先判断当前是否是节假日放假的日子 - 如果是的话 设为 -1 查询加班加班班次 如果不是的话 判断当前是否是补班 如果是的话设为8 为补班日 - 最后获取当前是周几后续判断这个周几是否是有班次 - 没有的话再查询下 -1 是否有加班班次
int week = isHolidayFlag != null && isHolidayFlag ? -1 : (isHolidayFlag != null ? 8 : dto.getLocalDateTime().getDayOfWeek().getValue());
AttendanceFixedDO attendanceFixedDO = this.getByGroupIdAndWeek(activationGroup.getId(), week);
// -- 当前没有班次 - 不需要考勤
if (attendanceFixedDO == null || attendanceFixedDO.getAttendanceGroupShiftId() == null) {
return vo.setTodayNeedAttendance(Constants.FALSE);
// -- 再获取一次加班班次 - 判断下是否有加班日 没有的话直接返回
if (week != -1) {
attendanceFixedDO = this.getByGroupIdAndWeek(activationGroup.getId(), -1);
if (attendanceFixedDO == null || attendanceFixedDO.getAttendanceGroupShiftId() == null) {
return vo.setTodayNeedAttendance(Constants.FALSE);
} else {
vo.setWorkOvertimeFlag(Constants.ONE);
}
} else {
return vo.setTodayNeedAttendance(Constants.FALSE);
}
} else if (week == -1) {
vo.setWorkOvertimeFlag(Constants.ONE);
}
vo.setAttendanceGroupShiftId(attendanceFixedDO.getAttendanceGroupShiftId());
attendanceService.calculatePunch(dto, vo);
@ -292,9 +300,9 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch
LocalDateTime localDateTime = LocalDateTimeUtil.parseDate(time, Constants.REPO_DATE_FORMAT).atStartOfDay();
Boolean holiday = attendanceService.isHoliday(localDateTime);
// -- 如果是节假日的话先插入下是节假日 - 不管上不上班
attendanceTimeRangeInfoVO.setDatType(holiday ? Constants.THREE : Constants.ONE);
Boolean isHolidayFlag = Constants.TRUE.equals(dto.getAutoHolidaysFlag()) ?
holiday : null;
attendanceTimeRangeInfoVO.setDatType(isHolidayFlag != null && isHolidayFlag ? Constants.THREE : Constants.ONE);
// -- 当前是节假日 并且是放假
if (isHolidayFlag != null && isHolidayFlag) {
map.put(time, attendanceTimeRangeInfoVO);

View File

@ -68,6 +68,11 @@ public interface AttendanceGroupService {
*/
List<AttendanceGroupDO> getAll();
/**
* 获取所有考勤组过滤绑定过加班规则的
* @return
*/
List<AttendanceGroupDO> getAllFilterWorkOvertimeRule(Long workOvertimeRuleId);
/**
* 获取使用班次id的考勤组ids
*

View File

@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.system.controller.admin.group.vo.AttendanceGroupPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.group.vo.AttendanceGroupSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.assets.AssetsDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.group.AttendanceGroupMapper;
@ -116,6 +115,11 @@ public class AttendanceGroupServiceImpl implements AttendanceGroupService {
return attendanceGroupMapper.selectList();
}
@Override
public List<AttendanceGroupDO> getAllFilterWorkOvertimeRule(Long workOvertimeRuleId) {
return attendanceGroupMapper.getAllFilterWorkOvertimeRule(workOvertimeRuleId);
}
@Override
public List<Long> getUseGroupIds(Long shiftId) {
List<Long> fixedGroupIds = attendanceFixedService.getUseGroupIds(shiftId);

View File

@ -11,25 +11,40 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendancePunchRecordDTO;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserDTO;
import cn.iocoder.yudao.module.system.convert.worklog.HolidayRemindConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.AttendanceGroupShiftItemDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaybalancesetting.HolidayBalanceSettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting.HolidaySettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuserrecord.HolidayUserRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.group.AttendanceGroupMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
import cn.iocoder.yudao.module.system.job.holiday.dto.HolidayRemindDTO;
import cn.iocoder.yudao.module.system.service.attendance.AttendanceService;
import cn.iocoder.yudao.module.system.service.attendance.fixed.AttendanceFixedService;
import cn.iocoder.yudao.module.system.service.attendance.groupshiftitem.AttendanceGroupShiftItemService;
import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO;
import cn.iocoder.yudao.module.system.service.attendance.scheduling.AttendanceSchedulingService;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.holiday.holidaybalancesetting.HolidayBalanceSettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysetting.HolidaySettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysettingrange.HolidaySettingRangeService;
import cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord.HolidayUserRecordService;
import cn.iocoder.yudao.module.system.service.holiday.holidayworkingage.HolidayWorkingAgeService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
@ -54,6 +69,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.PUNCH_RECO
* @author 艾楷
*/
@Service
@Slf4j
@Validated
public class AttendancePunchRecordServiceImpl extends ServiceImpl<AttendancePunchRecordMapper, AttendancePunchRecordDO> implements AttendancePunchRecordService {
@ -77,8 +93,6 @@ public class AttendancePunchRecordServiceImpl extends ServiceImpl<AttendancePunc
@Resource
@Lazy
private AdminUserService adminUserService;
// @Resource
// private BpmOALeaveApi bpmOALeaveApi;
@Override
public Long createPunchRecord(AttendancePunchRecordSaveReqVO createReqVO) {

View File

@ -227,7 +227,12 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ
AttendanceSchedulingDO attendanceSchedulingDO = this.getSchedulingByIndexDay(activationGroup.getId(), indexDay);
// -- 当前没有班次 - 不需要考勤
if (attendanceSchedulingDO == null || Constants.ONE.equals(attendanceSchedulingDO.getRestFlag()) || attendanceSchedulingDO.getAttendanceGroupShiftId() == null) {
return vo.setTodayNeedAttendance(Constants.FALSE);
attendanceSchedulingDO = this.getSchedulingByIndexDay(activationGroup.getId(), -1);
if (attendanceSchedulingDO == null || Constants.ONE.equals(attendanceSchedulingDO.getRestFlag()) || attendanceSchedulingDO.getAttendanceGroupShiftId() == null) {
return vo.setTodayNeedAttendance(Constants.FALSE);
} else {
vo.setWorkOvertimeFlag(Constants.ONE);
}
}
vo.setAttendanceGroupShiftId(attendanceSchedulingDO.getAttendanceGroupShiftId());
attendanceService.calculatePunch(dto, vo);
@ -321,10 +326,10 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ
// -- 判断是否根据节假日自动排班 - 如果是的话 - 根据排班的来
LocalDateTime localDateTime = LocalDateTimeUtil.parseDate(time, Constants.REPO_DATE_FORMAT).atStartOfDay();
Boolean holiday = attendanceService.isHoliday(localDateTime);
// -- 如果是节假日的话先插入下是节假日 - 不管上不上班
attendanceTimeRangeInfoVO.setDatType(holiday ? Constants.THREE : Constants.ONE);
Boolean isHolidayFlag = Constants.TRUE.equals(dto.getAutoHolidaysFlag()) ?
holiday : null;
// -- 如果是节假日的话先插入下是节假日 - 不管上不上班
attendanceTimeRangeInfoVO.setDatType(isHolidayFlag != null && isHolidayFlag ? Constants.THREE : Constants.ONE);
// -- 当前是节假日 并且是放假
if (isHolidayFlag != null && isHolidayFlag) {
map.put(time, attendanceTimeRangeInfoVO);

View File

@ -155,6 +155,7 @@ public class HolidaySettingServiceImpl implements HolidaySettingService {
return respVO;
}
// TODO: 2024/11/7 编辑的时候 没有发放当月 - 新增的时候没有历史
private void batchSave(HolidaySettingDO holidaySetting, HolidayBalanceSettingDO holidayBalanceSetting, List<HolidaySettingRangeDO> holidaySettingRanges, List<HolidayWorkingAgeDO> holidayWorkingAges) {
// ------- 插入假期设置
holidaySettingMapper.insert(holidaySetting);
@ -182,7 +183,7 @@ public class HolidaySettingServiceImpl implements HolidaySettingService {
}
// -- 计算假期
if (holidayBalanceSetting.getStatus() == 1) {
holidayUserRecordService.grant(holidaySetting, holidaySettingRanges, holidayBalanceSetting, holidayWorkingAges);
holidayUserRecordService.init(holidaySetting, holidaySettingRanges, holidayBalanceSetting, holidayWorkingAges);
}
}
@ -198,11 +199,22 @@ public class HolidaySettingServiceImpl implements HolidaySettingService {
LocalDateTime issueTime = null;
if (holidayBalanceSetting.getType() == 1) {
//获取下个月几号
issueTime = now.withDayOfMonth(holidayBalanceSetting.getIssueTimeType()).plusMonths(1);
//判断是否大于当前时间 - 如果是的话则已经有发放
LocalDateTime localDateTime = now.withDayOfMonth(holidayBalanceSetting.getIssueTimeType());
if (now.isBefore(localDateTime)) {
issueTime = localDateTime;
} else {
issueTime = localDateTime.plusMonths(1);
}
} else if (holidayBalanceSetting.getType() == 2) {
if (holidayBalanceSetting.getIssueTimeType() == 2) {
//获取明年1月1号
issueTime = now.plusYears(1).withMonth(Month.JANUARY.getValue()).withDayOfMonth(1);
LocalDateTime localDateTime = now.withMonth(Month.JANUARY.getValue()).withDayOfMonth(1);
if (now.isBefore(localDateTime)) {
issueTime = localDateTime;
} else {
issueTime = localDateTime.plusYears(1);
}
}
}
// -- 取一天的开始时间
@ -247,7 +259,7 @@ public class HolidaySettingServiceImpl implements HolidaySettingService {
@Override
public List<HolidaySettingDO> listByIds(List<Long> holidaySettingIds) {
if (CollectionUtil.isEmpty(holidaySettingIds)){
if (CollectionUtil.isEmpty(holidaySettingIds)) {
return Collections.emptyList();
}
return holidaySettingMapper.selectBatchIds(holidaySettingIds);

View File

@ -42,7 +42,7 @@ public interface HolidayUserRecordService {
void createUserHoliday(CreateUserHolidayDTO dto);
/**
* 创建用户请假(用于用户主动请假)
* 假期逾期
*
* @param holidayUserRecords
*/

View File

@ -236,7 +236,7 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
return holidayUserRecordMapper.selectList(new LambdaQueryWrapper<HolidayUserRecordDO>()
.eq(HolidayUserRecordDO::getUserId, userId)
.eq(HolidayUserRecordDO::getHolidaySettingId, holidaySettingId)
.orderByDesc(HolidayUserRecordDO::getReleaseTime));
.orderByDesc(HolidayUserRecordDO::getCreateTime));
}
@Override
@ -330,7 +330,8 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
holidayUserRecordDO.setRemark(remark + localDateTimeBigDecimalEntry.getValue() + (holidaySetting.getMinUnit() == 3 ? "小时" : "") + holidaySetting.getName());
holidayUserRecordDO.setReason(reason);
// -- 如果是0的话就不记录了
if (BigDecimal.ZERO.compareTo(holidayUserRecordDO.getHolidayBalance()) == 0) {
if (BigDecimal.ZERO.compareTo(holidayUserRecordDO.getHolidayBalance()) == 0
|| (expiredTime != null && expiredTime.isBefore(now))) {
continue;
}
newHolidayUserRecordDOList.add(holidayUserRecordDO);
@ -360,7 +361,7 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
List<HolidayUserDO> newHolidayUserDOList, LocalDateTime now, String remark, Integer direction, String reason) {
BigDecimal quota = userQuotaMap.get(userId);
// -- 如果是0的话就不记录了
if (BigDecimal.ZERO.compareTo(quota) == 0) {
if (quota == null || BigDecimal.ZERO.compareTo(quota) == 0) {
return;
}
HolidayUserDO holidayUserDO = holidayUserDOMap.get(userId);
@ -385,7 +386,8 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
holidayUserRecordDO.setExpirationReminderFlag(1);
holidayUserRecordDO.setExpiredDeductionFlag(1);
}
holidayUserRecordDO.setRemark(remark + quota + (holidaySetting.getMinUnit() == 3 ? "小时" : "") + holidaySetting.getName());
//quota保留两位小数
holidayUserRecordDO.setRemark(remark + quota.setScale(2, RoundingMode.HALF_UP) + (holidaySetting.getMinUnit() == 3 ? "小时" : "") + holidaySetting.getName());
holidayUserRecordDO.setReason(reason);
newHolidayUserRecordDOList.add(holidayUserRecordDO);
BigDecimal holidayBalance = holidayUserDO.getHolidayBalance().add(direction == 0 ? quota : quota.negate());
@ -619,6 +621,7 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
continue;
}
if (holidayBalanceSettingDO.getQuotaRule() == 1) {
// TODO: 2024/11/6 // -- actualWorkFlag 没有判断这个 - 暂时去掉
quotaMap.put(user.getId(), new BigDecimal(holidayBalanceSettingDO.getQuota().toString()));
} else {
Map<Integer, Integer> holidayWorkingAgeMap = holidayWorkingAgeDOS.stream().collect(Collectors.toMap(HolidayWorkingAgeDO::getYears, HolidayWorkingAgeDO::getNum));
@ -674,7 +677,7 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
List<HolidayUserDO> holidayUserDOS = holidayUserMapper.selectList(new LambdaQueryWrapper<HolidayUserDO>().eq(HolidayUserDO::getUserId, userId)
.eq(HolidayUserDO::getHolidaySettingId, dto.getHolidaySettingId()));
// 过滤掉不适用的
if (CollectionUtils.isEmpty(holidayUserDOS)){
if (CollectionUtils.isEmpty(holidayUserDOS)) {
return;
}
LocalDateTime now = LocalDateTime.now();
@ -714,12 +717,12 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
if (dto.getUnit() == 1) {
if (minUnit == 1 || minUnit == 2) {
// 转换为天 -
holidayBalance = dto.getHolidayBalance().divide(BigDecimal.valueOf(dto.getConversion()), 2, RoundingMode.HALF_UP);
holidayBalance = dto.getHolidayBalance().divide(dto.getConversion(), 2, RoundingMode.HALF_UP);
}
} else {
// -- 转换为小时
if (minUnit == 3) {
holidayBalance = dto.getHolidayBalance().multiply(BigDecimal.valueOf(dto.getConversion()));
holidayBalance = dto.getHolidayBalance().multiply(dto.getConversion());
}
}
return holidayBalance;

View File

@ -14,6 +14,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import javax.validation.Valid;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@ -106,8 +107,8 @@ public interface AdminUserService {
/**
* 修改用户编制
*
* @param id 用户编号
* @param userStaffing 编制
* @param id 用户编号
* @param userStaffing 编制
*/
void updateUserStaffing(Long id, Integer userStaffing);
@ -161,6 +162,7 @@ public interface AdminUserService {
/**
* 获取用户分页 - 带部门名称 -
*
* @param reqVO
* @return
*/
@ -398,8 +400,17 @@ public interface AdminUserService {
/**
* 获得指定身份证号码的用户列表
*
* @param idcards 身份证号码列表
* @return 用户列表
*/
List<AdminUserDO> getUserListByIdCard(List<String> idcards);
/**
* 更新用户入职时间
*
* @param id
* @param entryDate
*/
void updateUserEntryDate(Long id, LocalDateTime entryDate);
}

View File

@ -795,4 +795,9 @@ public class AdminUserServiceImpl implements AdminUserService {
return userMapper.selectList(new LambdaQueryWrapperX<AdminUserDO>()
.inIfPresent(AdminUserDO::getIdcard, idCards));
}
@Override
public void updateUserEntryDate(Long id, LocalDateTime entryDate) {
userMapper.updateById(new AdminUserDO().setId(id).setEntryDate(entryDate));
}
}

View File

@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.system.controller.admin.workovertime.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.workovertime.*;
import cn.iocoder.yudao.module.system.dal.mysql.workovertime.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.stereotype.Service;
@ -210,6 +211,9 @@ public class WorkOvertimeRuleServiceImpl implements WorkOvertimeRuleService {
public void deleteWorkOvertimeRule(Long id) {
// 删除
workOvertimeRuleMapper.deleteById(id);
// 同步删除考勤组加班规则关联数据
workOvertimeRuleAttendanceGroupMapper.delete(new LambdaQueryWrapper<WorkOvertimeRuleAttendanceGroupDO>()
.eq(WorkOvertimeRuleAttendanceGroupDO::getRuleId, id));
}
@Override

View File

@ -34,6 +34,10 @@
WHERE
a.deleted = 0
) as b on a.id = b.attendance_group_id
<if test="vo.userNickname != null and vo.userNickname != ''">
LEFT JOIN kq_attendance_group_user as c on a.id = c.attendance_group_id and c.deleted = 0
LEFT JOIN system_users as d on c.user_id = d.id and d.deleted = 0
</if>
<where>
a.deleted = 0
<if test="vo.groupName != null and vo.groupName != ''">
@ -59,7 +63,23 @@
#{userId}
</foreach>
</if>
<if test="vo.userNickname != null and vo.userNickname != ''">
and d.nickname like CONCAT( '%', #{vo.userNickname}, '%' )
</if>
</where>
GROUP BY a.id
</select>
<select id="getAllFilterWorkOvertimeRule"
resultType="cn.iocoder.yudao.module.system.dal.dataobject.attendance.group.AttendanceGroupDO">
select
a.*
from kq_attendance_group as a
<where>
NOT EXISTS ( SELECT 1 FROM kq_work_overtime_rule_attendance_group AS b WHERE b.attendance_group_id = a.id and deleted = 0
<if test="workOvertimeRuleId != null">
and rule_id != #{workOvertimeRuleId}
</if>
)
</where>
</select>
</mapper>

View File

@ -16,6 +16,7 @@
from kq_attendance_scheduling
where
deleted = 0
and index_day > 0
group by attendance_group_id
</select>
<select id="getUseGroupIds" resultType="java.lang.Long">

View File

@ -124,6 +124,9 @@
select a.*,b.name as deptName
from system_users as a
left join system_dept as b on a.dept_id = b.id
<if test="vo.groupIds != null and vo.groupIds.size() > 0">
left join kq_attendance_group_user c on a.id = c.user_id
</if>
<where>
a.deleted = 0
and a.user_type = 1
@ -153,6 +156,12 @@
#{deptId}
</foreach>
</if>
<if test="vo.groupIds != null and vo.groupIds.size() > 0">
and c.attendance_group_id in
<foreach collection="vo.groupIds" item="groupId" open="(" close=")" separator=",">
#{groupId}
</foreach>
</if>
</where>
</select>
</mapper>