feat(attendance): 按时间范围获取考勤信息

新增按时间范围获取用户考勤信息的功能,支持查询指定用户在一段时间内的考勤记录。主要变化包括:- 在 AdminUserDO 中添加 deptName 字段,用于存储部门名称
- 在 AttendanceApi 中添加 getAttendanceInfoByTimeRange 方法,用于获取考勤信息
- 在 AttendanceApiImpl 中实现 getAttendanceInfoByTimeRange 方法
- 在 AttendanceService 中添加 getAttendanceInfoByTimeRange 方法
- 在 AttendanceServiceImpl 中实现 getAttendanceInfoByTimeRange 方法- 在 AttendanceSchedulingServiceImpl 中添加相关逻辑
- 新增 AttendanceTimeRangeInfoDTO 和 AttendanceTimeRangeInfoVO 类用于传输考勤信息此功能可用于查询用户的考勤记录,包括正常出勤、请假、加班等情况。
This commit is contained in:
aikai 2024-10-24 15:52:50 +08:00
parent 1e51d4299d
commit 0902414ccf
89 changed files with 3317 additions and 461 deletions

View File

@ -163,6 +163,18 @@ public class DateUtils {
return calendar.getTime();
}
/**
* 创建指定时间
*
* @param timeStr 时间字符串格式为 HH:mm
* @return 指定时间
*/
public static LocalDateTime buildHHmmLocalDateTime(String timeStr, LocalDateTime localDateTime) {
String[] time = timeStr.split(":");
return localDateTime.withHour(Integer.parseInt(time[0])).withMinute(Integer.parseInt(time[1])).withSecond(0);
}
/**
* 创建指定时间
*
@ -405,6 +417,7 @@ public class DateUtils {
/**
* 毫秒转 **小时**分钟
*
* @param milliseconds
* @return
*/

View File

@ -7,11 +7,11 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;
/**
* 时间工具类用于 {@link java.time.LocalDateTime}
*
*/
public class LocalDateTimeUtils {
@ -121,4 +121,96 @@ public class LocalDateTimeUtils {
return date.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
}
/**
* 根据当前日期获取本季度最后一天
*
* @param dateTime
* @return
*/
public static LocalDateTime getQuarterEnd(LocalDateTime dateTime) {
int month = dateTime.getMonthValue();
int year = dateTime.getYear();
LocalDateTime quarterEnd = LocalDateTime.now();
if (month <= 3) {
quarterEnd = LocalDateTime.of(year, 3, 31, 23, 59, 59);
} else if (month <= 6) {
quarterEnd = LocalDateTime.of(year, 6, 30, 23, 59, 59);
} else if (month <= 9) {
quarterEnd = LocalDateTime.of(year, 9, 30, 23, 59, 59);
} else {
quarterEnd = LocalDateTime.of(year, 12, 31, 23, 59, 59);
}
return quarterEnd.with(TemporalAdjusters.lastDayOfMonth());
}
/**
* 获取至某一个时间每一个月的某一天
*
* @param beginTime
* @param endTime
* @param day
*/
public static List<LocalDateTime> getTheDayOfEachMonthSoFar(LocalDateTime beginTime, LocalDateTime endTime, int day) {
List<LocalDateTime> monthlyFirstDays = new ArrayList<>();
while (!beginTime.isAfter(endTime)) {
// 获取当月的1号
LocalDateTime firstDayOfMonth = beginTime.withDayOfMonth(day);
// 添加到列表
monthlyFirstDays.add(firstDayOfMonth);
// 移动到下个月
beginTime = beginTime.plusMonths(1);
}
return monthlyFirstDays;
}
/**
* 获取至某一个时间每年的一月一号
*
* @param beginTime
* @param endTime
*/
public static List<LocalDateTime> getTheDayOfEachYeasSoFar(LocalDateTime beginTime, LocalDateTime endTime) {
List<LocalDateTime> monthlyFirstDays = new ArrayList<>();
while (!beginTime.isAfter(endTime)) {
// 获取当月的1号
LocalDateTime firstDayOfMonth = beginTime.withDayOfYear(1);
// 添加到列表
monthlyFirstDays.add(firstDayOfMonth);
// 移动到下个月
beginTime = beginTime.plusYears(1);
}
return monthlyFirstDays;
}
/**
* 获取至某一个时间每年当前日期
*
* @param beginTime
* @param endTime
*/
public static List<LocalDateTime> getTheCurrentDateOfEachYearToACertainTime(LocalDateTime beginTime, LocalDateTime endTime) {
List<LocalDateTime> monthlyFirstDays = new ArrayList<>();
while (!beginTime.isAfter(endTime)) {
// 添加到列表
monthlyFirstDays.add(beginTime);
// 移动到下个年
beginTime = beginTime.plusYears(1);
}
return monthlyFirstDays;
}
/**
* 判断两个时间范围是否相交 true false
*/
public static boolean intersects(LocalDateTime start, LocalDateTime end, LocalDateTime otherStart, LocalDateTime otherEnd) {
// 判断两个时间范围是否相交
return !end.isBefore(otherStart) && !otherEnd.isBefore(start);
}
}

View File

@ -21,6 +21,11 @@ public interface ErrorCodeConstants {
ErrorCode OA_HR_POST_NOT_EXISTS = new ErrorCode(1_009_001_006, "HR岗位未设置");
ErrorCode OA_DAY_LEAVE_ERROR = new ErrorCode(1_009_001_007, "请假天数必须>=1");
ErrorCode FAILED_TO_APPLY_FOR_LEAVE = new ErrorCode(1_009_001_008, "请假失败");
ErrorCode WRONG_TIME_FORMAT = new ErrorCode(1_009_001_009, "时间格式错误");
ErrorCode THERE_IS_ALREADY_A_RECORD_OF_REQUESTING_LEAVE_DURING_THIS_TIME_PERIOD = new ErrorCode(1_009_001_010, "该时间段内已有请假记录,请调整");
ErrorCode GET_USER_HOLIDAY_EXCEPTION = new ErrorCode(1_009_001_011, "获取用户假期异常");
ErrorCode THE_USER_ATTENDANCE_INFORMATION_IS_ABNORMAL = new ErrorCode(1_009_001_012, "获取用户考勤信息异常");
ErrorCode INSUFFICIENT_LEAVE_BALANCE = new ErrorCode(1_009_001_013, "假期余额不足");
ErrorCode OA_REIMBURSEMENT_NOT_EXISTS = new ErrorCode(1_009_001_100, "报销申请不存在");
ErrorCode OA_EVECTION_NOT_EXISTS = new ErrorCode(1_009_001_101, "出差申请不存在");

View File

@ -1,9 +1,11 @@
package cn.iocoder.yudao.module.bpm.enums.task;
import cn.hutool.core.collection.ListUtil;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -48,6 +50,10 @@ public enum BpmProcessInstanceResultEnum {
* 能被减签的状态
*/
public static final List<Integer> CAN_SUB_SIGN_STATUS_LIST = Arrays.asList(PROCESS.result, WAIT_BEFORE_TASK.result);
/**
* 处理中or通过 状态
*/
public static final List<Integer> PROCESSING_OR_PASSED = processingOrPassed();
/**
* 结果
@ -74,4 +80,22 @@ public enum BpmProcessInstanceResultEnum {
SIGN_AFTER.getResult());
}
/**
* 获取所有类型
*
* @return
*/
public static List<Integer> getAllResult() {
List<Integer> resultList = new ArrayList<>();
Arrays.stream(BpmProcessInstanceResultEnum.class.getEnumConstants())
.map(BpmProcessInstanceResultEnum::getResult)
.forEach(resultList::add);
return resultList;
}
public static List<Integer> processingOrPassed() {
List<Integer> allResult = getAllResult();
allResult.removeAll(Arrays.asList(REJECT.result,CANCEL.result));
return allResult;
}
}

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeaveCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeavePageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeaveRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.CalculateAndVerifyLeaveDTO;
import cn.iocoder.yudao.module.bpm.convert.oa.BpmOALeaveConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService;
@ -16,6 +17,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.math.BigDecimal;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@ -24,7 +26,6 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
* OA 请假申请 Controller
*
* @author jason
*/
@Tag(name = "管理后台 - OA 请假申请")
@RestController
@ -36,12 +37,17 @@ public class BpmOALeaveController {
private BpmOALeaveService leaveService;
@PostMapping("/create")
// @PreAuthorize("@ss.hasPermission('bpm:oa-leave:create')")
@Operation(summary = "创建请求申请")
@Operation(summary = "创建请假申请")
public CommonResult<Long> createLeave(@Valid @RequestBody BpmOALeaveCreateReqVO createReqVO) {
return success(leaveService.createLeave(getLoginUserId(), createReqVO));
}
@PostMapping("/calculateAndVerifyTheNumberOfLeaveDays")
@Operation(summary = "计算请假时长")
public CommonResult<BigDecimal> calculateAndVerifyTheNumberOfLeaveDays(@Valid @RequestBody CalculateAndVerifyLeaveDTO dto) {
return success(leaveService.calculateAndVerifyTheNumberOfLeaveDays(getLoginUserId(), dto));
}
@GetMapping("/get")
// @PreAuthorize("@ss.hasPermission('bpm:oa-leave:query')")
@Operation(summary = "获得请假申请")

View File

@ -27,9 +27,9 @@ public class BpmOALeaveBaseVO {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime endTime;
@Schema(description = "请假类型-参见 bpm_oa_leave_type 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "请假类型不能为空")
private Integer type;
@Schema(description = "假期设置id", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
@NotNull(message = "假期设置id")
private Long holidaySettingId;
@Schema(description = "原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
@NotNull(message = "原因不能为空")

View File

@ -1,20 +1,71 @@
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.AssertTrue;
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - 请假申请创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmOALeaveCreateReqVO extends BpmOALeaveBaseVO {
public class BpmOALeaveCreateReqVO {
@AssertTrue(message = "结束时间,需要在开始时间之后")
public boolean isEndTimeValid() {
return !getEndTime().isBefore(getStartTime());
@Schema(description = "假期设置id", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
@NotNull(message = "假期设置id")
private Long holidaySettingId;
@Schema(description = "请假的开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate startTime;
@Schema(description = "请假的结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate endTime;
@Schema(description = "请假时长 (单位根据请假最小单位来 按天or按半天 单位为天 按小时单位为小时)", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
private BigDecimal duration;
@Schema(description = "开始时间额外字段 根据请假最小单位来 1按天则为空 2按半天则1为上午 2为下午 3按小时则 格式为 HH:mm", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
private String startTimeExtraFields;
@Schema(description = "结束时间额外字段 根据请假最小单位来 1按天则为空 2按半天则1为上午 2为下午 3按小时则 格式为 HH:mm", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
private String endTimeExtraFields;
@Schema(description = "请假最小单位 1按天 2按半天 3按小时", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
@NotNull(message = "请假最小单位 1按天 2按半天 3按小时")
private Integer minUnit;
@Schema(description = "原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
@NotNull(message = "原因不能为空")
private String reason;
@Schema(description = "流程实例编号")
private String processInstanceId;
@Schema(description = "状态-参见 bpm_process_instance_result 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer result;
@Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED)
private List<UploadUserFile> fileItems;
public LocalDateTime getStartTime() {
return this.startTime.atStartOfDay();
}
public LocalDateTime getEndTime() {
return this.endTime.atStartOfDay();
}
}

View File

@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ -20,8 +21,9 @@ public class BpmOALeavePageReqVO extends PageParam {
@Schema(description = "状态-参见 bpm_process_instance_result 枚举", example = "1")
private Integer result;
@Schema(description = "请假类型-参见 bpm_oa_type", example = "1")
private Integer type;
@Schema(description = "假期设置id", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
@NotNull(message = "假期设置id")
private Long holidaySettingId;
@Schema(description = "原因-模糊匹配", example = "阅读芋道源码")
private String reason;

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Data
public class CalculateAndVerifyLeaveDTO {
@Schema(description = "假期设置id", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
@NotNull(message = "假期设置id")
private Long holidaySettingId;
@Schema(description = "请假的开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate startTime;
@Schema(description = "请假的结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate endTime;
@Schema(description = "开始时间额外字段 根据请假最小单位来 1按天则为空 2按半天则1为上午 2为下午 3按小时则 格式为 HH:mm", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
private String startTimeExtraFields;
@Schema(description = "结束时间额外字段 根据请假最小单位来 1按天则为空 2按半天则1为上午 2为下午 3按小时则 格式为 HH:mm", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
private String endTimeExtraFields;
@Schema(description = "请假最小单位 1按天 2按半天 3按小时", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
@NotNull(message = "请假最小单位 1按天 2按半天 3按小时")
private Integer minUnit;
@Schema(description = "用户id (前端不用传)", requiredMode = Schema.RequiredMode.REQUIRED, example = "阅读芋道源码")
private Long userId;
public LocalDateTime getStartTime() {
return this.startTime.atStartOfDay();
}
public LocalDateTime getEndTime() {
return this.endTime.atStartOfDay();
}
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.convert.oa;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeaveCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeaveRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.CalculateAndVerifyLeaveDTO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@ -27,4 +28,5 @@ public interface BpmOALeaveConvert {
PageResult<BpmOALeaveRespVO> convertPage(PageResult<BpmOALeaveDO> page);
BpmOALeaveDO convertCalculateLeaveDTO(CalculateAndVerifyLeaveDTO dto);
}

View File

@ -1,26 +1,26 @@
package cn.iocoder.yudao.module.bpm.dal.dataobject.oa;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
* OA 请假申请 DO
*
* {@link #day} 请假天数目前先简单做一般是分成请假上午和下午可以是 1 整天可以是 0.5 半天
*
* @author jason
*/
@TableName(value ="bpm_oa_leave", autoResultMap = true)
@TableName(value = "bpm_oa_leave", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@ -36,18 +36,22 @@ public class BpmOALeaveDO extends BaseDO {
private Long id;
/**
* 申请人的用户编号
*
* <p>
* 关联 AdminUserDO id 属性
*/
private Long userId;
/**
* 请假类型
* 假期设置id
*/
private String type;
private Long holidaySettingId;
/**
* 原因
*/
private String reason;
/**
* 假期名称
*/
private String leaveName;
/**
* 开始时间
*/
@ -56,13 +60,28 @@ public class BpmOALeaveDO extends BaseDO {
* 结束时间
*/
private LocalDateTime endTime;
/**
* 请假天数
* 请假时长单位根据请假最小单位来 按天or按半天 单位为天 按小时单位为小时
*/
private Long day;
private BigDecimal duration;
/**
* 开始时间额外字段 根据请假最小单位来 1按天则为空 2按半天则1为上午 2为下午 3按小时则 格式为 HH:mm
*/
private String startTimeExtraFields;
/**
* 结束时间额外字段 根据请假最小单位来 1按天则为空 2按半天则1为上午 2为下午 3按小时则 格式为 HH:mm
*/
private String endTimeExtraFields;
/**
* 请假最小单位 1按天 2按半天 3按小时
*/
private Integer minUnit;
/**
* 请假的结果
*
* <p>
* 枚举 {@link BpmProcessInstanceResultEnum}
* 考虑到简单所以直接复用了 BpmProcessInstanceResultEnum 枚举也可以自己定义一个枚举哈
*/
@ -70,7 +89,7 @@ public class BpmOALeaveDO extends BaseDO {
/**
* 对应的流程编号
*
* <p>
* 关联 ProcessInstance id 属性
*/
private String processInstanceId;
@ -79,6 +98,6 @@ public class BpmOALeaveDO extends BaseDO {
* 附件基本信息
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<UploadUserFile> fileItems ;
private List<UploadUserFile> fileItems;
}

View File

@ -24,7 +24,6 @@ public interface BpmOALeaveMapper extends BaseMapperX<BpmOALeaveDO> {
return selectPage(reqVO, new LambdaQueryWrapperX<BpmOALeaveDO>()
.eqIfPresent(BpmOALeaveDO::getUserId, userId)
.eqIfPresent(BpmOALeaveDO::getResult, reqVO.getResult())
.eqIfPresent(BpmOALeaveDO::getType, reqVO.getType())
.likeIfPresent(BpmOALeaveDO::getReason, reqVO.getReason())
.betweenIfPresent(BpmOALeaveDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(BpmOALeaveDO::getId));

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.PostApi;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.equipment.UsersExtApi;
import cn.iocoder.yudao.module.system.api.holiday.HolidayApi;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.position.PositionApi;
@ -22,7 +23,7 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@EnableFeignClients(clients = {FileApi.class, RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class, NotifyMessageSendApi.class,
SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class, AttendanceApi.class, BankApi.class, ConfigApi.class, PositionApi.class, SupplierApi.class, AssetsApi.class
SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class, AttendanceApi.class, BankApi.class, ConfigApi.class, PositionApi.class, SupplierApi.class, AssetsApi.class, HolidayApi.class
})
public class RpcConfiguration {
}

View File

@ -5,23 +5,24 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeaveCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeavePageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.CalculateAndVerifyLeaveDTO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.List;
/**
* 请假申请 Service 接口
*
* @author jason
*/
public interface BpmOALeaveService {
/**
* 创建请假申请
*
* @param userId 用户编号
* @param userId 用户编号
* @param createReqVO 创建信息
* @return 编号
*/
@ -30,7 +31,7 @@ public interface BpmOALeaveService {
/**
* 更新请假申请的状态
*
* @param id 编号
* @param id 编号
* @param result 结果
*/
void updateLeaveResult(Long id, Integer result);
@ -46,7 +47,7 @@ public interface BpmOALeaveService {
/**
* 获得请假申请分页
*
* @param userId 用户编号
* @param userId 用户编号
* @param pageReqVO 分页查询
* @return 请假申请分页
*/
@ -54,6 +55,7 @@ public interface BpmOALeaveService {
/**
* 根据时间获取请假列表
*
* @param time
* @return
*/
@ -61,8 +63,18 @@ public interface BpmOALeaveService {
/**
* 获得指定请假申请
*
* @param processInstanceId 流程实例编号
* @return 出差申请
*/
BpmOALeaveDO getByProcessInstanceId(String processInstanceId);
/**
* 计算请假时长
*
* @param loginUserId
* @param dto
* @return
*/
BigDecimal calculateAndVerifyTheNumberOfLeaveDays(Long loginUserId, CalculateAndVerifyLeaveDTO dto);
}

View File

@ -4,15 +4,19 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.pojo.BpmOALeaveDTO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.oa.vo.BpmOALeaveRpcVO;
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.leave.BpmOALeaveCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeavePageReqVO;
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.CalculateAndVerifyLeaveDTO;
import cn.iocoder.yudao.module.bpm.convert.oa.BpmOALeaveConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOALeaveMapper;
@ -20,20 +24,29 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService;
import cn.iocoder.yudao.module.system.api.attendance.AttendanceApi;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendancePunchRecordDTO;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendanceTimeRangeInfoDTO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceGroupShiftItemVO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceTimeRangeInfoVO;
import cn.iocoder.yudao.module.system.api.holiday.HolidayApi;
import cn.iocoder.yudao.module.system.api.holiday.dto.CreateUserHolidayDTO;
import cn.iocoder.yudao.module.system.api.holiday.vo.HolidaySettingVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.FAILED_TO_APPLY_FOR_LEAVE;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_LEAVE_NOT_EXISTS;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
/**
* OA 请假申请 Service 实现类
@ -58,49 +71,564 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav
private StringRedisTemplate stringRedisTemplate;
@Resource
private AttendanceApi attendanceApi;
@Resource
private BpmHistoryProcessInstanceService historyProcessInstanceService;
@Resource
private HolidayApi holidayApi;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createLeave(Long userId, BpmOALeaveCreateReqVO createReqVO) {
// 插入 OA 请假单
long day = LocalDateTimeUtil.between(createReqVO.getStartTime(), createReqVO.getEndTime()).toDays();
BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convert(createReqVO).setUserId(userId).setDay(day)
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())
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
// 构建请假开始 or 结束时间
LocalDateTime[] times = this.builderLeaveTime(leave);
// -- 判断是否有重复时间
if (CollectionUtil.isNotEmpty(bpmOALeaveDOS)) {
for (BpmOALeaveDO bpmOALeaveDO : bpmOALeaveDOS) {
LocalDateTime[] itemTimes = this.builderLeaveTime(bpmOALeaveDO);
boolean intersects = LocalDateTimeUtils.intersects(times[0], times[1], itemTimes[0], itemTimes[1]);
if (intersects) {
throw exception(THERE_IS_ALREADY_A_RECORD_OF_REQUESTING_LEAVE_DURING_THIS_TIME_PERIOD);
}
}
}
// -- 计算用户假期 -- 内含 判断假期是否充足
BigDecimal duration = this.calculateAndVerifyTheNumberOfLeaveDays(leave);
// 插入 OA 请假单
leaveMapper.insert(leave);
// 发起 BPM 流程
Map<String, Object> processInstanceVariables = new HashMap<>();
processInstanceVariables.put("day", day);
processInstanceVariables.put("duration", leave.getDuration());
String processInstanceId = processInstanceApi.createProcessInstance(userId,
new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(leave.getId()))).getCheckedData();
// 将工作流的编号更新到 OA 请假单中
leaveMapper.updateById(new BpmOALeaveDO().setId(leave.getId()).setProcessInstanceId(processInstanceId));
// 判断是否为重新发起的流程
if (createReqVO.getProcessInstanceId() != null && createReqVO.getResult() == 3) {
historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId());
}
List<UploadUserFile> fileItems = createReqVO.getFileItems();
//这里的逻辑如果fileItems不为空且有数据那么说明是上传了附件的则需要更工作流文件表对应的实例Id
if (fileItems != null && !fileItems.isEmpty()) {
uploadBpmFileProcessInstanceId(processInstanceId, fileItems);
}
// 创建完流程后 - 减去对应用户的假期余额 - 记录请假原因
String beginTimeStr = "";
String endTimeStr = "";
if (leave.getMinUnit() == 2) {
beginTimeStr = "1".equals(leave.getStartTimeExtraFields()) ? "上午" : "下午";
endTimeStr = "2".equals(leave.getStartTimeExtraFields()) ? "上午" : "下午";
}
String reason = "开始时间:" + leave.getStartTime().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY)) + " " + beginTimeStr +
" 结束时间:" + leave.getEndTime().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY)) + " " + endTimeStr;
holidayApi.createUserHoliday(new CreateUserHolidayDTO().setUserId(leave.getUserId()).setHolidaySettingId(leave.getHolidaySettingId())
.setDirection(1).setHolidayBalance(duration).setReason(reason));
return leave.getId();
}
/**
* 计算校验用户假期余额是否充足
*
* @param leave
*/
private BigDecimal calculateAndVerifyTheNumberOfLeaveDays(BpmOALeaveDO leave) {
//-- 判断用户假期额度是否充足 - 根据假期配置来计算出请假时长先
CommonResult<HolidaySettingVO> holidaySettings = holidayApi.getHolidaySettings(leave.getUserId(), leave.getHolidaySettingId());
if (!holidaySettings.isSuccess() || holidaySettings.getData() == null) {
throw exception(GET_USER_HOLIDAY_EXCEPTION);
}
HolidaySettingVO vo = holidaySettings.getCheckedData();
leave.setLeaveName(vo.getName());
// 计算请假多久 - ok 怎么计算
// 先判断是什么类型的请假然后计算请假时长
// --- - 这里还要根据用户的考勤组计算 - 计算是否是工作时间 妈的
Integer minUnit = leave.getMinUnit();
BigDecimal duration = BigDecimal.ZERO;
// -- 先拿到请假的这几天 - 完了后去获取当前用户所在考勤组这几天是否需要工作 - 是不是工作时间
if (vo.getCalculationMethod() == 0) {
if (minUnit == 1) {
// 按天
// -- 如果是同一天的话 +1
duration = new BigDecimal(String.valueOf(LocalDateTimeUtil.between(leave.getStartTime(), leave.getEndTime(), ChronoUnit.DAYS) + 1));
} else if (minUnit == 2) {
// -- 按半天
duration = new BigDecimal(String.valueOf(LocalDateTimeUtil.between(leave.getStartTime(), leave.getEndTime(), ChronoUnit.DAYS) + 1));
if (leave.getStartTimeExtraFields().equals(leave.getEndTimeExtraFields())) {
duration = duration.subtract(new BigDecimal("0.5"));
} else if (Integer.parseInt(leave.getStartTimeExtraFields()) > Integer.parseInt(leave.getEndTimeExtraFields())) {
duration = duration.subtract(BigDecimal.ONE);
}
} else {
// 按小时
// -- 计算出相差的分钟
long betweenMinutes = LocalDateTimeUtil.between(leave.getStartTime(), leave.getEndTime(), ChronoUnit.MINUTES);
duration = this.hourRounding(vo.getRoundFlag(), vo.getRoundUnit(), vo.getRoundDirection(), betweenMinutes);
}
} else {
//获取当前登录用户所在考勤组 以及每天的班次
Map<String, AttendanceTimeRangeInfoVO> dataList = this.getAttendanceInfoByTimeRange(new AttendanceTimeRangeInfoDTO()
.setUserId(leave.getUserId()).setStartTime(leave.getStartTime()).setEndTime(leave.getEndTime()));
List<String> list = DateUtils.betweenDayList(leave.getStartTime(), leave.getEndTime());
if (minUnit == 1) {
for (String time : list) {
AttendanceTimeRangeInfoVO attendanceTimeRangeInfoVO = dataList.get(time);
if (attendanceTimeRangeInfoVO == null || attendanceTimeRangeInfoVO.getNeedAttendance().equals(0)
|| CollectionUtil.isEmpty(attendanceTimeRangeInfoVO.getItems())) {
continue;
}
duration = duration.add(BigDecimal.ONE);
}
} else if (minUnit == 2) {
// -- 按半天
// -- 假设每天都需要上班 那么直接看第一天的开始时间和最后一天的结束时间即可 - 那么 也有可能他其中也有不上班的 - 不上班的话 - 去一天
BigDecimal withoutWorkDayNum = BigDecimal.ZERO;
duration = new BigDecimal(String.valueOf(LocalDateTimeUtil.between(leave.getStartTime(), leave.getEndTime(), ChronoUnit.DAYS) + 1));
if (leave.getStartTimeExtraFields().equals(leave.getEndTimeExtraFields())) {
duration = duration.subtract(new BigDecimal("0.5"));
} else if (Integer.parseInt(leave.getStartTimeExtraFields()) > Integer.parseInt(leave.getEndTimeExtraFields())) {
duration = duration.subtract(BigDecimal.ONE);
}
for (String time : list) {
AttendanceTimeRangeInfoVO attendanceTimeRangeInfoVO = dataList.get(time);
if (attendanceTimeRangeInfoVO == null || attendanceTimeRangeInfoVO.getNeedAttendance().equals(0)
|| CollectionUtil.isEmpty(attendanceTimeRangeInfoVO.getItems())) {
LocalDateTime thisTime = LocalDateTimeUtil.parseDate(time, Constants.REPO_DATE_FORMAT).atStartOfDay();
if (LocalDateTimeUtil.isSameDay(thisTime, leave.getStartTime())) {
// -- 如果是开始时间
if (Objects.equals(leave.getStartTimeExtraFields(), "1")) {
withoutWorkDayNum = withoutWorkDayNum.add(BigDecimal.ONE);
} else {
withoutWorkDayNum = withoutWorkDayNum.add(new BigDecimal("0.5"));
}
} else if (LocalDateTimeUtil.isSameDay(thisTime, leave.getEndTime())) {
// -- 如果是结束时间
if (Objects.equals(leave.getStartTimeExtraFields(), "1")) {
withoutWorkDayNum = withoutWorkDayNum.add(new BigDecimal("0.5"));
} else {
withoutWorkDayNum = withoutWorkDayNum.add(BigDecimal.ONE);
}
} else {
withoutWorkDayNum = withoutWorkDayNum.add(BigDecimal.ONE);
}
}
}
duration = duration.subtract(withoutWorkDayNum);
} else {
long totalWorkMinutes = 0;
for (String time : list) {
AttendanceTimeRangeInfoVO attendanceTimeRangeInfoVO = dataList.get(time);
if (attendanceTimeRangeInfoVO == null || attendanceTimeRangeInfoVO.getNeedAttendance().equals(0)
|| CollectionUtil.isEmpty(attendanceTimeRangeInfoVO.getItems())) {
continue;
}
// 获取当天时间 - 转为LocalDateTime
LocalDateTime thisTime = LocalDateTimeUtil.parseDate(time, Constants.REPO_DATE_FORMAT).atStartOfDay();
// 升序从小到大
List<AttendanceGroupShiftItemVO> items = attendanceTimeRangeInfoVO.getItems().stream()
.sorted(Comparator.comparingInt(AttendanceGroupShiftItemVO::getLevel))
.collect(Collectors.toList());
AttendanceGroupShiftItemVO first = CollectionUtil.getFirst(items);
AttendanceGroupShiftItemVO last = CollectionUtil.getLast(items);
LocalDateTime beginTime = DateUtils.buildHHmmLocalDateTime(first.getBeginTime(), thisTime);
LocalDateTime lastTime = thisTime;
if (Arrays.asList(1, 2).contains(last.getNextDayFlag())) {
lastTime = lastTime.plusDays(1);
}
LocalDateTime endTime = DateUtils.buildHHmmLocalDateTime(last.getEndTime(), lastTime);
// -- 间隔的时间
long intervalTime = 0L;
int size = items.size();
if (size > 1) {
for (int i = 0; i < size - 1; i++) {
// -- 第一天的话不可能所有时间都跨天 只可能是结束时间跨天
LocalDateTime top = DateUtils.buildHHmmLocalDateTime(items.get(i).getBeginTime(), thisTime);
LocalDateTime next = DateUtils.buildHHmmLocalDateTime(items.get(i + 1).getEndTime(), thisTime);
// -- 只有这种情况需要设置下跨天
if (items.get(i).getNextDayFlag() == 0 && items.get(i + 1).getNextDayFlag() == 1) {
next = next.plusDays(1);
}
long between = LocalDateTimeUtil.between(top, next, ChronoUnit.MINUTES);
intervalTime = intervalTime + between;
}
}
// -- 一天的时间
long betweenMinutes = LocalDateTimeUtil.between(beginTime, endTime, ChronoUnit.MINUTES) - intervalTime;
// -- 一天中休息的时间 (请假开始和结束时间特殊处理过)
long allRestTime = 0L;
for (AttendanceGroupShiftItemVO item : items) {
LocalDateTime workBeginTime = DateUtils.buildHHmmLocalDateTime(item.getBeginTime(), thisTime);
LocalDateTime workEndTime = DateUtils.buildHHmmLocalDateTime(item.getEndTime(), thisTime);
if (Arrays.asList(1, 2).contains(item.getNextDayFlag())) {
workEndTime = workEndTime.plusDays(1);
}
boolean beginSameDayFlag = LocalDateTimeUtil.isSameDay(thisTime, leave.getStartTime());
if (beginSameDayFlag) {
// 如果请假开始时间 = 当前时间
// 判断开始时间是否是上班时间
boolean flag = LocalDateTimeUtil.isIn(leave.getStartTime(), workBeginTime, workEndTime);
if (flag) {
// 如果请假时间在当前时间段 - 再去判断 是否再休息时间段内 - 如果是再休息时间段内的话 拿休息结束时间当作请假开始时间
if (item.getRestFlag() == 1) {
// -- 这里分三个情况 - 1.在工作开始时间 休息开始时间内 2.在休息时间内 3.在休息结束时间到工作结束时间
LocalDateTime restBeginTime = DateUtils.buildHHmmLocalDateTime(item.getRestBeginTime(), lastTime);
LocalDateTime restEndTime = DateUtils.buildHHmmLocalDateTime(item.getRestEndTime(), lastTime);
// -- 如果休息的结束时间小于休息的开始时间 - 说明跨天了
if (restBeginTime.isAfter(restEndTime)) {
restEndTime = restEndTime.plusDays(1);
}
long restTime = LocalDateTimeUtil.between(restBeginTime, restEndTime, ChronoUnit.MINUTES);
if (LocalDateTimeUtil.isIn(leave.getStartTime(), workBeginTime, restBeginTime)) {
allRestTime = allRestTime + LocalDateTimeUtil.between(workBeginTime, leave.getStartTime(), ChronoUnit.MINUTES) + restTime;
} else if (LocalDateTimeUtil.isIn(leave.getStartTime(), restBeginTime, restEndTime)) {
allRestTime = allRestTime + LocalDateTimeUtil.between(workBeginTime, restBeginTime, ChronoUnit.MINUTES) + restTime;
} else if (LocalDateTimeUtil.isIn(leave.getStartTime(), restEndTime, workEndTime)) {
// -- 休息时间 = 工作开始时间 请假开始时间 - 期间的休息时间(因为总的已经减过了)
allRestTime = allRestTime + LocalDateTimeUtil.between(workBeginTime, leave.getStartTime(), ChronoUnit.MINUTES);
}
} else {
allRestTime = allRestTime + LocalDateTimeUtil.between(workBeginTime, leave.getStartTime(), ChronoUnit.MINUTES);
}
} else {
// -- 如果请假时间不在当前工作时间段内段话则把当前工作时间当做休息时间 -
allRestTime = allRestTime + LocalDateTimeUtil.between(workBeginTime, workEndTime, ChronoUnit.MINUTES);
}
}
boolean endSameDayFlag = LocalDateTimeUtil.isSameDay(thisTime, leave.getEndTime());
if (endSameDayFlag) {
boolean flag = LocalDateTimeUtil.isIn(leave.getEndTime(), workBeginTime, workEndTime);
if (flag) {
// 如果请假时间在当前时间段 - 再去判断 是否再休息时间段内 - 如果是再休息时间段内的话 拿休息结束时间当作请假开始时间
if (item.getRestFlag() == 1) {
// -- 这里分三个情况 - 1.在工作开始时间 休息开始时间内 2.在休息时间内 3.在休息结束时间到工作结束时间
LocalDateTime restBeginTime = DateUtils.buildHHmmLocalDateTime(item.getRestBeginTime(), lastTime);
LocalDateTime restEndTime = DateUtils.buildHHmmLocalDateTime(item.getRestEndTime(), lastTime);
// -- 如果休息的结束时间小于休息的开始时间 - 说明跨天了
if (restBeginTime.isAfter(restEndTime)) {
restEndTime = restEndTime.plusDays(1);
}
long restTime = LocalDateTimeUtil.between(restBeginTime, restEndTime, ChronoUnit.MINUTES);
if (LocalDateTimeUtil.isIn(leave.getEndTime(), workBeginTime, restBeginTime)) {
allRestTime = allRestTime + LocalDateTimeUtil.between(leave.getEndTime(), workEndTime, ChronoUnit.MINUTES);
} else if (LocalDateTimeUtil.isIn(leave.getEndTime(), restBeginTime, restEndTime)) {
allRestTime = allRestTime + LocalDateTimeUtil.between(restBeginTime, workEndTime, ChronoUnit.MINUTES);
} else if (LocalDateTimeUtil.isIn(leave.getEndTime(), restEndTime, workEndTime)) {
// -- 这里需要判断 请假开始时间和结束时间是不是同一天 - 如果是同一天的话 就会出现重复扣除休息时间的情况 - 所以要避免这个情况
if (beginSameDayFlag) {
allRestTime = allRestTime + LocalDateTimeUtil.between(leave.getEndTime(), workEndTime, ChronoUnit.MINUTES);
} else {
allRestTime = allRestTime + LocalDateTimeUtil.between(leave.getEndTime(), workEndTime, ChronoUnit.MINUTES) + restTime;
}
}
} else {
allRestTime = allRestTime + LocalDateTimeUtil.between(leave.getEndTime(), workEndTime, ChronoUnit.MINUTES);
}
}
}
if (!beginSameDayFlag && !endSameDayFlag) {
if (item.getRestFlag() == 1) {
LocalDateTime restBeginTime = DateUtils.buildHHmmLocalDateTime(item.getRestBeginTime(), lastTime);
LocalDateTime restEndTime = DateUtils.buildHHmmLocalDateTime(item.getRestEndTime(), lastTime);
// -- 如果休息的结束时间小于休息的开始时间 - 说明跨天了
if (restBeginTime.isAfter(restEndTime)) {
restEndTime = restEndTime.plusDays(1);
}
long restTime = LocalDateTimeUtil.between(restBeginTime, restEndTime, ChronoUnit.MINUTES);
// -- 休息时间 = 工作开始时间 请假开始时间 - 期间的休息时间(因为总的已经减过了)
allRestTime = allRestTime + restTime;
}
}
}
// -- 总的时间 减去休息时间
betweenMinutes = betweenMinutes - allRestTime;
totalWorkMinutes = totalWorkMinutes + betweenMinutes;
}
// 按小时
duration = this.hourRounding(vo.getRoundFlag(), vo.getRoundUnit(), vo.getRoundDirection(), totalWorkMinutes);
}
}
if (vo.getStatus() == 1 && vo.getHolidayBalance() != null && vo.getHolidayBalance().compareTo(duration) < 0) {
throw exception(INSUFFICIENT_LEAVE_BALANCE);
}
return duration;
}
/**
* 小时计算取整
*
* @param roundFlag
* @param roundUnit
* @param roundDirection
* @param totalWorkMinutes
* @return
*/
private BigDecimal hourRounding(Integer roundFlag, Integer roundUnit, Integer roundDirection, long totalWorkMinutes) {
BigDecimal roundedDuration;
if (roundFlag == 0) {
return BigDecimal.valueOf(totalWorkMinutes).divide(BigDecimal.valueOf(60.0), 2, RoundingMode.HALF_UP);
} else {
if (roundUnit == 0) {
// 按半小时取整
if (roundDirection == 0) {
// 向下取整
roundedDuration = BigDecimal.valueOf(Math.floor(totalWorkMinutes / 30.0) * 30).divide(BigDecimal.valueOf(60.0), 2, RoundingMode.HALF_UP);
} else {
// 向上取整
roundedDuration = BigDecimal.valueOf(Math.ceil(totalWorkMinutes / 30.0) * 30).divide(BigDecimal.valueOf(60.0), 2, RoundingMode.HALF_UP);
}
} else {
// 按一个小时取整
if (roundDirection == 0) {
// 向下取整
roundedDuration = BigDecimal.valueOf(Math.floor(totalWorkMinutes / 60.0) * 60).divide(BigDecimal.valueOf(60.0), 2, RoundingMode.HALF_UP);
} else {
// 向上取整
roundedDuration = BigDecimal.valueOf(Math.ceil(totalWorkMinutes / 60.0) * 60).divide(BigDecimal.valueOf(60.0), 2, RoundingMode.HALF_UP);
}
}
}
return roundedDuration;
}
public static void main(String[] args) {
// 请假时间
LocalDateTime startLeaveTime = LocalDateTime.of(2023, 4, 1, 13, 0);
// LocalDateTime startLeaveTime = LocalDateTime.of(2023, 4, 1, 11:20, 0);
LocalDateTime endLeaveTime = LocalDateTime.of(2023, 4, 1, 15, 20);
long totalWorkMinutes = 0;
// List<String> list = Arrays.asList("2023-04-01", "2023-04-02", "2023-04-03", "2023-04-04", "2023-04-05");
List<String> list = Arrays.asList("2023-04-01");
Map<String, AttendanceTimeRangeInfoVO> dataList = new HashMap<>();
dataList.put("2023-04-01", new AttendanceTimeRangeInfoVO().setNeedAttendance(1)
.setItems(Arrays.asList(new AttendanceGroupShiftItemVO().setLevel(1).setBeginTime("09:00").setEndTime("18:00").setRestFlag(1).setRestBeginTime("12:00").setRestEndTime("14:00"))));
// dataList.put("2023-04-02", new AttendanceTimeRangeInfoVO().setNeedAttendance(0).setItems(Arrays.asList(new AttendanceGroupShiftItemVO().setLevel(1).setBeginTime("09:00").setEndTime("18:00"))));
// dataList.put("2023-04-03", new AttendanceTimeRangeInfoVO().setNeedAttendance(0).setItems(Arrays.asList(new AttendanceGroupShiftItemVO().setLevel(1).setBeginTime("09:00").setEndTime("18:00"))));
// dataList.put("2023-04-04", new AttendanceTimeRangeInfoVO().setNeedAttendance(1)
// .setItems(Arrays.asList(
// new AttendanceGroupShiftItemVO().setLevel(1).setBeginTime("09:00").setEndTime("18:00").setRestFlag(1).setRestBeginTime("12:00").setRestEndTime("14:00"),
// new AttendanceGroupShiftItemVO().setLevel(2).setBeginTime("22:00").setEndTime("2:00").setNextDayFlag(2).setRestFlag(1).setRestBeginTime("23:00").setRestEndTime("01:00"))));
for (String time : list) {
AttendanceTimeRangeInfoVO attendanceTimeRangeInfoVO = dataList.get(time);
if (attendanceTimeRangeInfoVO == null || attendanceTimeRangeInfoVO.getNeedAttendance().equals(0)
|| CollectionUtil.isEmpty(attendanceTimeRangeInfoVO.getItems())) {
continue;
}
// 获取当天时间 - 转为LocalDateTime
LocalDateTime thisTime = LocalDateTimeUtil.parseDate(time, Constants.REPO_DATE_FORMAT).atStartOfDay();
// 升序从小到大
List<AttendanceGroupShiftItemVO> items = attendanceTimeRangeInfoVO.getItems().stream()
.sorted(Comparator.comparingInt(AttendanceGroupShiftItemVO::getLevel))
.collect(Collectors.toList());
AttendanceGroupShiftItemVO first = CollectionUtil.getFirst(items);
AttendanceGroupShiftItemVO last = CollectionUtil.getLast(items);
LocalDateTime beginTime = DateUtils.buildHHmmLocalDateTime(first.getBeginTime(), thisTime);
LocalDateTime lastTime = thisTime;
if (Arrays.asList(1, 2).contains(last.getNextDayFlag())) {
lastTime = lastTime.plusDays(1);
}
LocalDateTime endTime = DateUtils.buildHHmmLocalDateTime(last.getEndTime(), lastTime);
// -- 间隔的时间
long intervalTime = 0L;
int size = items.size();
if (size > 1) {
for (int i = 0; i < size - 1; i++) {
// -- 第一天的话不可能所有时间都跨天 只可能是结束时间跨天
LocalDateTime top = DateUtils.buildHHmmLocalDateTime(items.get(i).getBeginTime(), thisTime);
LocalDateTime next = DateUtils.buildHHmmLocalDateTime(items.get(i + 1).getEndTime(), thisTime);
// -- 只有这种情况需要设置下跨天
if (items.get(i).getNextDayFlag() == 0 && items.get(i + 1).getNextDayFlag() == 1) {
next = next.plusDays(1);
}
long between = LocalDateTimeUtil.between(top, next, ChronoUnit.MINUTES);
intervalTime = intervalTime + between;
}
}
// -- 一天的时间
long betweenMinutes = LocalDateTimeUtil.between(beginTime, endTime, ChronoUnit.MINUTES) - intervalTime;
// -- 一天中休息的时间 (请假开始和结束时间特殊处理过)
long allRestTime = 0L;
for (AttendanceGroupShiftItemVO vo : items) {
LocalDateTime workBeginTime = DateUtils.buildHHmmLocalDateTime(vo.getBeginTime(), thisTime);
LocalDateTime workEndTime = DateUtils.buildHHmmLocalDateTime(vo.getEndTime(), thisTime);
if (Arrays.asList(1, 2).contains(vo.getNextDayFlag())) {
workEndTime = workEndTime.plusDays(1);
}
boolean beginSameDayFlag = LocalDateTimeUtil.isSameDay(thisTime, startLeaveTime);
if (beginSameDayFlag) {
// 如果请假开始时间 = 当前时间
// 判断开始时间是否是上班时间
boolean flag = LocalDateTimeUtil.isIn(startLeaveTime, workBeginTime, workEndTime);
if (flag) {
// 如果请假时间在当前时间段 - 再去判断 是否再休息时间段内 - 如果是再休息时间段内的话 拿休息结束时间当作请假开始时间
if (vo.getRestFlag() == 1) {
// -- 这里分三个情况 - 1.在工作开始时间 休息开始时间内 2.在休息时间内 3.在休息结束时间到工作结束时间
LocalDateTime restBeginTime = DateUtils.buildHHmmLocalDateTime(vo.getRestBeginTime(), lastTime);
LocalDateTime restEndTime = DateUtils.buildHHmmLocalDateTime(vo.getRestEndTime(), lastTime);
// -- 如果休息的结束时间小于休息的开始时间 - 说明跨天了
if (restBeginTime.isAfter(restEndTime)) {
restEndTime = restEndTime.plusDays(1);
}
long restTime = LocalDateTimeUtil.between(restBeginTime, restEndTime, ChronoUnit.MINUTES);
if (LocalDateTimeUtil.isIn(startLeaveTime, workBeginTime, restBeginTime)) {
allRestTime = allRestTime + LocalDateTimeUtil.between(workBeginTime, startLeaveTime, ChronoUnit.MINUTES) + restTime;
} else if (LocalDateTimeUtil.isIn(startLeaveTime, restBeginTime, restEndTime)) {
allRestTime = allRestTime + LocalDateTimeUtil.between(workBeginTime, restBeginTime, ChronoUnit.MINUTES) + restTime;
} else if (LocalDateTimeUtil.isIn(startLeaveTime, restEndTime, workEndTime)) {
// -- 休息时间 = 工作开始时间 请假开始时间 - 期间的休息时间(因为总的已经减过了)
allRestTime = allRestTime + LocalDateTimeUtil.between(workBeginTime, startLeaveTime, ChronoUnit.MINUTES);
}
} else {
allRestTime = allRestTime + LocalDateTimeUtil.between(workBeginTime, startLeaveTime, ChronoUnit.MINUTES);
}
} else {
// -- 如果请假时间不在当前工作时间段内段话则把当前工作时间当做休息时间 -
allRestTime = allRestTime + LocalDateTimeUtil.between(workBeginTime, workEndTime, ChronoUnit.MINUTES);
}
}
boolean endSameDayFlag = LocalDateTimeUtil.isSameDay(thisTime, endLeaveTime);
if (endSameDayFlag) {
boolean flag = LocalDateTimeUtil.isIn(endLeaveTime, workBeginTime, workEndTime);
if (flag) {
// 如果请假时间在当前时间段 - 再去判断 是否再休息时间段内 - 如果是再休息时间段内的话 拿休息结束时间当作请假开始时间
if (vo.getRestFlag() == 1) {
// -- 这里分三个情况 - 1.在工作开始时间 休息开始时间内 2.在休息时间内 3.在休息结束时间到工作结束时间
LocalDateTime restBeginTime = DateUtils.buildHHmmLocalDateTime(vo.getRestBeginTime(), lastTime);
LocalDateTime restEndTime = DateUtils.buildHHmmLocalDateTime(vo.getRestEndTime(), lastTime);
// -- 如果休息的结束时间小于休息的开始时间 - 说明跨天了
if (restBeginTime.isAfter(restEndTime)) {
restEndTime = restEndTime.plusDays(1);
}
long restTime = LocalDateTimeUtil.between(restBeginTime, restEndTime, ChronoUnit.MINUTES);
if (LocalDateTimeUtil.isIn(endLeaveTime, workBeginTime, restBeginTime)) {
allRestTime = allRestTime + LocalDateTimeUtil.between(endLeaveTime, workEndTime, ChronoUnit.MINUTES);
} else if (LocalDateTimeUtil.isIn(endLeaveTime, restBeginTime, restEndTime)) {
allRestTime = allRestTime + LocalDateTimeUtil.between(restBeginTime, workEndTime, ChronoUnit.MINUTES);
} else if (LocalDateTimeUtil.isIn(endLeaveTime, restEndTime, workEndTime)) {
// -- 这里需要判断 请假开始时间和结束时间是不是同一天 - 如果是同一天的话 就会出现重复扣除休息时间的情况 - 所以要避免这个情况
if (beginSameDayFlag) {
allRestTime = allRestTime + LocalDateTimeUtil.between(endLeaveTime, workEndTime, ChronoUnit.MINUTES);
} else {
allRestTime = allRestTime + LocalDateTimeUtil.between(endLeaveTime, workEndTime, ChronoUnit.MINUTES) + restTime;
}
}
} else {
allRestTime = allRestTime + LocalDateTimeUtil.between(endLeaveTime, workEndTime, ChronoUnit.MINUTES);
}
}
}
if (!beginSameDayFlag && !endSameDayFlag) {
if (vo.getRestFlag() == 1) {
LocalDateTime restBeginTime = DateUtils.buildHHmmLocalDateTime(vo.getRestBeginTime(), lastTime);
LocalDateTime restEndTime = DateUtils.buildHHmmLocalDateTime(vo.getRestEndTime(), lastTime);
// -- 如果休息的结束时间小于休息的开始时间 - 说明跨天了
if (restBeginTime.isAfter(restEndTime)) {
restEndTime = restEndTime.plusDays(1);
}
long restTime = LocalDateTimeUtil.between(restBeginTime, restEndTime, ChronoUnit.MINUTES);
// -- 休息时间 = 工作开始时间 请假开始时间 - 期间的休息时间(因为总的已经减过了)
allRestTime = allRestTime + restTime;
}
}
}
// -- 总的时间 减去休息时间
betweenMinutes = betweenMinutes - allRestTime;
totalWorkMinutes = totalWorkMinutes + betweenMinutes;
}
System.out.println(totalWorkMinutes);
}
/**
* 按时间范围获取出勤信息
*
* @param attendanceTimeRangeInfoDTO
* @return
*/
private Map<String, AttendanceTimeRangeInfoVO> getAttendanceInfoByTimeRange(AttendanceTimeRangeInfoDTO attendanceTimeRangeInfoDTO) {
CommonResult<Map<String, AttendanceTimeRangeInfoVO>> attendanceInfoByTimeRange = attendanceApi.getAttendanceInfoByTimeRange(attendanceTimeRangeInfoDTO);
if (!attendanceInfoByTimeRange.isSuccess()) {
throw exception(THE_USER_ATTENDANCE_INFORMATION_IS_ABNORMAL);
}
return attendanceInfoByTimeRange.getData();
}
/**
* 构建请假开始结束时间 -
*
* @return
*/
private LocalDateTime[] builderLeaveTime(BpmOALeaveDO leave) {
LocalDateTime startTime = leave.getStartTime();
LocalDateTime endTime = leave.getEndTime();
if (leave.getMinUnit() == 1) {
startTime = LocalDateTimeUtil.beginOfDay(startTime);
endTime = LocalDateTimeUtil.endOfDay(endTime);
} else if (leave.getMinUnit() == 2) {
if ("1".equals(leave.getStartTimeExtraFields())) {
// -- 如果开始时间是1 - 则设为0点开始
startTime = LocalDateTimeUtil.beginOfDay(startTime);
} else {
startTime = startTime.withHour(12).withMinute(0).withSecond(0);
}
if ("1".equals(leave.getEndTimeExtraFields())) {
endTime = endTime.withHour(12).withMinute(0).withSecond(0);
} else {
endTime = LocalDateTimeUtil.endOfDay(endTime);
}
} else if (leave.getMinUnit() == 3) {
String[] split = leave.getStartTimeExtraFields().split(":");
startTime = startTime.withHour(Integer.parseInt(split[0])).withMinute(Integer.parseInt(split[1])).withSecond(0);
split = leave.getEndTimeExtraFields().split(":");
endTime = endTime.withHour(Integer.parseInt(split[0])).withMinute(Integer.parseInt(split[1])).withSecond(0);
} else {
throw exception(WRONG_TIME_FORMAT);
}
leave.setStartTime(startTime);
leave.setEndTime(endTime);
return new LocalDateTime[]{startTime, endTime};
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateLeaveResult(Long id, Integer result) {
BpmOALeaveDO bpmOALeaveDO = validateLeaveExists(id);
BpmOALeaveDO leave = validateLeaveExists(id);
leaveMapper.updateById(new BpmOALeaveDO().setId(id).setResult(result));
// -- 如果是通过 - 则判断当前时间是否是请假开始时间前
// -- 如果是的话 先插入到redis中 - (事前请假)
@ -110,24 +638,27 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav
if (result.equals(BpmProcessInstanceResultEnum.APPROVE.getResult())) {
// 事后请假修改考勤 = 考勤的预设已经生成过了 - 并且已经在表里面存在了 - 所以要找到表中的数据 - 修改考勤状态
CommonResult commonResult = attendanceApi.askingForLeaveAfterwardsToModifyAttendance(new AttendancePunchRecordDTO()
.setUserId(bpmOALeaveDO.getUserId())
.setStartTime(bpmOALeaveDO.getStartTime())
.setEndTime(bpmOALeaveDO.getEndTime())
.setUserId(leave.getUserId())
.setStartTime(leave.getStartTime())
.setEndTime(leave.getEndTime())
.setLeaveId(id)
.setLeaveType(bpmOALeaveDO.getType())
.setLeaveName(leave.getLeaveName())
);
if (!commonResult.isSuccess()) {
throw exception(FAILED_TO_APPLY_FOR_LEAVE);
}
if (now.isBefore(bpmOALeaveDO.getEndTime())) {
if (now.isBefore(leave.getEndTime())) {
// 事前请假 = 考勤预设可能还没有生成 - 因为可能请假好几天 - 所以这里处理就比较麻烦点 - 先看下考勤表里面有没有在这个区间的考勤 - 如果有的话先修改考勤状态 -
// 然后将数据先存入redis - 在设置考勤预设的时候 就去redis 中查询是否有请假 - 有的话预设的时候就预设进去
BpmOALeaveDTO dto = new BpmOALeaveDTO();
BeanUtil.copyProperties(bpmOALeaveDO, dto);
String key = "leave" + "_" + bpmOALeaveDO.getUserId().toString();
BeanUtil.copyProperties(leave, dto);
String key = "leave" + "_" + leave.getUserId().toString();
stringRedisTemplate.opsForHash().put(key, id.toString(), JSONUtil.toJsonStr(dto));
// -- 将请假put到redis的map中 -
}
} else if (Arrays.asList(BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult()).contains(result)) {
holidayApi.createUserHoliday(new CreateUserHolidayDTO().setUserId(leave.getUserId()).setHolidaySettingId(leave.getHolidaySettingId())
.setDirection(0).setHolidayBalance(leave.getDuration()).setReason("请假审核不通过返回假期余额"));
}
}
@ -163,4 +694,11 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav
}
return list.get(0);
}
@Override
public BigDecimal calculateAndVerifyTheNumberOfLeaveDays(Long loginUserId, CalculateAndVerifyLeaveDTO dto) {
BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convertCalculateLeaveDTO(dto).setUserId(loginUserId);
this.builderLeaveTime(leave);
return this.calculateAndVerifyTheNumberOfLeaveDays(leave);
}
}

View File

@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.springframework.context.annotation.Lazy;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

View File

@ -1,17 +1,16 @@
package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import lombok.*;
import java.time.LocalTime;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_HOUR_MINUTE_SECOND;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 自提门店分页 Request VO")

View File

@ -2,7 +2,9 @@ package cn.iocoder.yudao.module.system.api.attendance;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendancePunchRecordDTO;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendanceTimeRangeInfoDTO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendancePunchRecordVO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceTimeRangeInfoVO;
import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -11,6 +13,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
import java.util.Map;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 考勤")
@ -23,4 +26,9 @@ public interface AttendanceApi {
@PostMapping(PREFIX + "/askingForLeaveAfterwardsToModifyAttendance")
@Operation(summary = "获取考勤记录")
CommonResult askingForLeaveAfterwardsToModifyAttendance(@RequestBody AttendancePunchRecordDTO attendancePunchRecordDTO);
@PostMapping(PREFIX + "/getAttendanceInfoByTimeRange")
@Operation(summary = "获取考勤记录")
CommonResult<Map<String, AttendanceTimeRangeInfoVO>> getAttendanceInfoByTimeRange(@RequestBody AttendanceTimeRangeInfoDTO attendanceTimeRangeInfoDTO);
}

View File

@ -30,7 +30,7 @@ public class AttendancePunchRecordDTO {
*/
private Long leaveId;
/**
* 请假类型
* 请假名称
*/
private String leaveType;
private String leaveName;
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.system.api.attendance.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* @author 艾楷
*/
@Data
public class AttendanceTimeRangeInfoDTO {
/**
* 用户id
*/
private Long userId;
/**
* 开始时间
*/
@Schema(description = "开始时间")
private LocalDateTime startTime;
/**
* 结束时间
*/
@Schema(description = "结束时间")
private LocalDateTime endTime;
/**
* 时间列表yyyy-MM-dd格式
*/
@Schema(description = "时间列表yyyy-MM-dd格式")
private List<String> times;
/**
* 节假日自动排休 0否 1是
*/
private Integer autoHolidaysFlag;
/**
* 考勤组id
*/
private Long groupId;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.system.api.attendance.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* @author 艾楷
*/
@Data
public class AttendanceGroupShiftItemVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "957")
private Long id;
@Schema(description = "班次id", example = "22909")
private Long kqAttendanceGroupShiftId;
@Schema(description = "级别 从1到 排序用")
private Integer level;
@Schema(description = "开始打卡时间")
private String beginTime;
@Schema(description = "结束打卡时间")
private String endTime;
@Schema(description = "是否次日(开始时间 大于 结束时间)跨天 0否 1跨天 2结束时间跨天")
private Integer nextDayFlag;
@Schema(description = "是否开启中间时间段休息 0否 1是")
private Integer restFlag;
@Schema(description = "休息开始时间 HH:mm")
private String restBeginTime;
@Schema(description = "休息结束时间 HH:mm")
private String restEndTime;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.api.attendance.vo;
import cn.hutool.core.collection.ListUtil;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 用户打卡记录 DO
*
* @author 艾楷
*/
@Data
public class AttendanceTimeRangeInfoVO {
/**
* 是否需要考勤
*/
@Schema(description = "是否需要考勤 0否 1是")
private Integer needAttendance = 0;
/**
* 当日班次信息
*/
@Schema(description = "班次子表信息")
private List<AttendanceGroupShiftItemVO> items = ListUtil.empty();
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.system.api.holiday;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.holiday.dto.CreateUserHolidayDTO;
import cn.iocoder.yudao.module.system.api.holiday.vo.HolidaySettingVO;
import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 假期")
public interface HolidayApi {
String PREFIX = ApiConstants.PREFIX + "/holiday";
@PostMapping(PREFIX + "/getHolidaySettings")
@Operation(summary = "获取假期设置")
CommonResult<HolidaySettingVO> getHolidaySettings(@RequestParam("userId") Long userId,
@RequestParam("holidaySettingId") Long holidaySettingId);
@PostMapping(PREFIX + "/createUserHoliday")
@Operation(summary = "创建用户请假")
CommonResult createUserHoliday(@RequestBody CreateUserHolidayDTO dto);
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.api.holiday.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class CreateUserHolidayDTO {
@Schema(description = "用户id", example = "18256")
private Long userId;
@Schema(description = "假期设置id", example = "25199")
private Long holidaySettingId;
@Schema(description = "操作方向 0新增 1减去")
private Integer direction;
@Schema(description = "假期余额(这里的单位根据假期设置的来 没有固定单位)")
private BigDecimal holidayBalance;
@Schema(description = "原由")
private String reason;
}

View File

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.system.api.holiday.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class HolidaySettingVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24863")
private Long id;
@Schema(description = "假期规则名称", example = "赵六")
private String name;
@Schema(description = "应用范围 0全公司 1指定(记录在kq_holiday_setting_range 表中)", example = "赵六")
private Integer applicationScope;
@Schema(description = "新员工请假类型 1入职即可请假 2转正后才可请假", example = "2")
private Integer newEmployeeLeaveType;
@Schema(description = "是否带薪 0否 1是")
private Integer salaryFlag;
@Schema(description = "请假最小单位 1按天 2按半天 3按小时")
private Integer minUnit;
@Schema(description = "请假取整 0否 1是")
private Integer roundFlag;
@Schema(description = "取整方向 0向下 1向上 (需要取整才有意义)")
private Integer roundDirection;
@Schema(description = "取整单位 0按半小时 1按小时 (需要取整才有意义)")
private Integer roundUnit;
@Schema(description = "请假计算方式 0按自然日计算休息日也会记录请假 1按工作日计算请假时段中不包含员工的休息日")
private Integer calculationMethod;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
@Schema(description = "当前用户该假期余额余额")
private BigDecimal holidayBalance;
@Schema(description = "假期设置状态 0关闭 1开启")
private Integer status;
}

View File

@ -206,7 +206,7 @@
</goals>
</execution>
</executions>
</plugin>
</plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>8</source><target>8</target></configuration></plugin>
</plugins>
</build>

View File

@ -2,11 +2,16 @@ package cn.iocoder.yudao.module.system.api.attendance;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendancePunchRecordDTO;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendanceTimeRangeInfoDTO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceTimeRangeInfoVO;
import cn.iocoder.yudao.module.system.service.attendance.AttendanceService;
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
@ -14,11 +19,18 @@ public class AttendanceApiImpl implements AttendanceApi {
@Resource
private AttendancePunchRecordService attendancePunchRecordService;
@Resource
private AttendanceService attendanceService;
@Override
public CommonResult askingForLeaveAfterwardsToModifyAttendance(AttendancePunchRecordDTO attendancePunchRecordDTO) {
attendancePunchRecordService.askingForLeaveAfterwardsToModifyAttendance(attendancePunchRecordDTO);
return CommonResult.success("ok");
}
@Override
public CommonResult<Map<String, AttendanceTimeRangeInfoVO>> getAttendanceInfoByTimeRange(AttendanceTimeRangeInfoDTO attendanceTimeRangeInfoDTO) {
return CommonResult.success(attendanceService.getAttendanceInfoByTimeRange(attendanceTimeRangeInfoDTO));
}
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.system.api.holiday;
import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.holiday.dto.CreateUserHolidayDTO;
import cn.iocoder.yudao.module.system.api.holiday.vo.HolidaySettingVO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting.HolidaySettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuser.HolidayUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.holiday.holidayuser.HolidayUserMapper;
import cn.iocoder.yudao.module.system.service.holiday.holidaysetting.HolidaySettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord.HolidayUserRecordService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
public class HolidayApiImpl implements HolidayApi {
@Resource
private HolidaySettingService holidaySettingService;
@Resource
private HolidayUserMapper holidayUserMapper;
@Resource
private HolidayUserRecordService holidayUserRecordService;
@Override
public CommonResult<HolidaySettingVO> getHolidaySettings(Long userId, Long holidaySettingId) {
HolidaySettingVO vo = new HolidaySettingVO();
HolidaySettingDO holidaySetting = holidaySettingService.getHolidaySetting(holidaySettingId);
HolidayUserDO holidayUserDO = holidayUserMapper.selectOne(new LambdaQueryWrapper<HolidayUserDO>().eq(HolidayUserDO::getHolidaySettingId, holidaySettingId).eq(HolidayUserDO::getUserId, userId));
BeanUtil.copyProperties(holidaySetting, vo);
vo.setHolidayBalance(holidayUserDO == null ? null : holidayUserDO.getHolidayBalance());
vo.setStatus(holidaySetting.getHolidayBalanceSettingDO().getStatus());
return CommonResult.success(vo);
}
@Override
public CommonResult createUserHoliday(CreateUserHolidayDTO dto) {
holidayUserRecordService.createUserHoliday(dto);
return CommonResult.success("ok");
}
}

View File

@ -33,6 +33,18 @@ public class AttendanceGroupShiftItemRespVO {
@ExcelProperty("结束打卡时间")
private String endTime;
@Schema(description = "是否开启中间时间段休息 0否 1是")
@ExcelProperty("是否开启中间时间段休息 0否 1是")
private Integer restFlag;
@Schema(description = "休息开始时间 HH:mm")
@ExcelProperty("休息开始时间 HH:mm")
private String restBeginTime;
@Schema(description = "休息结束时间 HH:mm")
@ExcelProperty("休息结束时间 HH:mm")
private String restEndTime;
@Schema(description = "是否必须 0否 1是 (如果不是必须系统会自动打卡)")
@ExcelProperty("是否必须 0否 1是 (如果不是必须系统会自动打卡)")
private Integer mustFlag;
@ -61,4 +73,4 @@ public class AttendanceGroupShiftItemRespVO {
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}
}

View File

@ -26,6 +26,18 @@ public class AttendanceGroupShiftItemSaveReqVO {
@Schema(description = "结束打卡时间")
private String endTime;
@Schema(description = "是否开启中间时间段休息 0否 1是")
@ExcelProperty("是否开启中间时间段休息 0否 1是")
private Integer restFlag;
@Schema(description = "休息开始时间 HH:mm")
@ExcelProperty("休息开始时间 HH:mm")
private String restBeginTime;
@Schema(description = "休息结束时间 HH:mm")
@ExcelProperty("休息结束时间 HH:mm")
private String restEndTime;
@Schema(description = "是否必须 0否 1是 (如果不是必须系统会自动打卡)")
private Integer mustFlag;
@ -44,4 +56,4 @@ public class AttendanceGroupShiftItemSaveReqVO {
@Schema(description = "下班后打卡时间(分钟) 默认 120分钟")
private Integer afterPunchTimeDownWork;
}
}

View File

@ -24,10 +24,10 @@ public class HolidayBalanceSettingPageReqVO extends PageParam {
@Schema(description = "发放方式 1每月自动发放 2每年自动发放 3手动发放 4加班时长自动计入余额", example = "2")
private Integer type;
@Schema(description = "发放日期 1每月n日 2每年员工入职日 3每年1月1日", example = "1")
@Schema(description = "发放日期 当发放方式为每月自动发放时 该值代表的是几号 当发放方式为每年自动发放时 该值代表 1每年员工入职日 2每年1月1日", example = "1")
private Integer issueTimeType;
@Schema(description = "发放日期(设置好后 插入发放日期 - 发放完成后插入下一次发放日期) 如果是 null 的话代表手动发放和加班自动计算")
@Schema(description = "发放日期(设置好后 插入发放日期 - 发放完成后插入下一次发放日期) 如果是 null 的话代表手动发放和加班自动计算或者每年员工入职日")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] issueTime;
@ -40,14 +40,14 @@ public class HolidayBalanceSettingPageReqVO extends PageParam {
@Schema(description = "是否按实际工作时长发放 0否 1是(例如每年1月1日发放6天假期入职时间是6月1日的员工则按照半年发放3天假期当余额出现小数时按四舍五入取整)")
private Integer actualWorkFlag;
@Schema(description = "有效期类型 1自发放日起1个月 2自发放日起1周年 3按入职日期起12个月 4自然年1月1日-12月31日 5每年固定时间作废 6加班多少天后作废 7永久有效 8每月固定时间作废 9每季末作废")
@Schema(description = "有效期类型 1自发放日起1个月 2自发放日起1周年 3按入职日期起12个月 4自然年1月1日-12月31日 5每年固定时间作废 6永久有效 7每月固定时间作废 8每季末作废")
private Integer validityPeriod;
@Schema(description = "每年固定时间作废格式 MM-dd 例如 09-10 每年9月10号作废", example = "12794")
private String fixedEveryYearInvalid;
@Schema(description = "灵活作废时间 根据有效期类型代表不同意思")
private Integer invalidFlexible;
@Schema(description = "每月固定时间作废 格式 1 or 4 or 7 or 10")
private Integer fixedEveryMonthInvalid;
@Schema(description = "是否允许延长有效期 0否 1是")
private Integer extensionAllowedFlag;

View File

@ -31,12 +31,12 @@ public class HolidayBalanceSettingRespVO {
@ExcelProperty("发放方式 1每月自动发放 2每年自动发放 3手动发放 4加班时长自动计入余额")
private Integer type;
@Schema(description = "发放日期 1每月n日 2每年员工入职日 3每年1月1日", example = "1")
@ExcelProperty("发放日期 1每月n日 2每年员工入职日 3每年1月1日")
@Schema(description = "发放日期 当发放方式为每月自动发放时 该值代表的是几号 当发放方式为每年自动发放时 该值代表 1每年员工入职日 2每年1月1日", example = "1")
@ExcelProperty("发放日期 当发放方式为每月自动发放时 该值代表的是几号 当发放方式为每年自动发放时 该值代表 1每年员工入职日 2每年1月1日")
private Integer issueTimeType;
@Schema(description = "发放日期(设置好后 插入发放日期 - 发放完成后插入下一次发放日期) 如果是 null 的话代表手动发放和加班自动计算")
@ExcelProperty("发放日期(设置好后 插入发放日期 - 发放完成后插入下一次发放日期) 如果是 null 的话代表手动发放和加班自动计算")
@Schema(description = "发放日期(设置好后 插入发放日期 - 发放完成后插入下一次发放日期) 如果是 null 的话代表手动发放和加班自动计算或者每年员工入职日")
@ExcelProperty("发放日期(设置好后 插入发放日期 - 发放完成后插入下一次发放日期) 如果是 null 的话代表手动发放和加班自动计算或者每年员工入职日")
private LocalDateTime issueTime;
@Schema(description = "额度规则 1固定规则 2按工龄 0代表自动发放或者加班自动计算")
@ -51,17 +51,17 @@ public class HolidayBalanceSettingRespVO {
@ExcelProperty("是否按实际工作时长发放 0否 1是(例如每年1月1日发放6天假期入职时间是6月1日的员工则按照半年发放3天假期当余额出现小数时按四舍五入取整)")
private Integer actualWorkFlag;
@Schema(description = "有效期类型 1自发放日起1个月 2自发放日起1周年 3按入职日期起12个月 4自然年1月1日-12月31日 5每年固定时间作废 6加班多少天后作废 7永久有效 8每月固定时间作废 9每季末作废")
@ExcelProperty("有效期类型 1自发放日起1个月 2自发放日起1周年 3按入职日期起12个月 4自然年1月1日-12月31日 5每年固定时间作废 6加班多少天后作废 7永久有效 8每月固定时间作废 9每季末作废")
@Schema(description = "有效期类型 1自发放日起1个月 2自发放日起1周年 3按入职日期起12个月 4自然年1月1日-12月31日 5每年固定时间作废 6永久有效 7每月固定时间作废 8每季末作废")
@ExcelProperty("有效期类型 1自发放日起1个月 2自发放日起1周年 3按入职日期起12个月 4自然年1月1日-12月31日 5每年固定时间作废 6永久有效 7每月固定时间作废 8每季末作废")
private Integer validityPeriod;
@Schema(description = "每年固定时间作废格式 MM-dd 例如 09-10 每年9月10号作废", example = "12794")
@ExcelProperty("每年固定时间作废格式 MM-dd 例如 09-10 每年9月10号作废")
private String fixedEveryYearInvalid;
@Schema(description = "灵活作废时间 根据有效期类型代表不同意思")
@ExcelProperty("灵活作废时间 根据有效期类型代表不同意思")
private Integer invalidFlexible;
@Schema(description = "每月固定时间作废 格式 1 or 4 or 7 or 10")
@ExcelProperty("每月固定时间作废 格式 1 or 4 or 7 or 10")
private Integer fixedEveryMonthInvalid;
@Schema(description = "是否允许延长有效期 0否 1是")
@ExcelProperty("是否允许延长有效期 0否 1是")

View File

@ -23,10 +23,10 @@ public class HolidayBalanceSettingSaveReqVO {
@Schema(description = "发放方式 1每月自动发放 2每年自动发放 3手动发放 4加班时长自动计入余额", example = "2")
private Integer type;
@Schema(description = "发放日期 1每月n日 2每年员工入职日 3每年1月1日", example = "1")
@Schema(description = "发放日期 当发放方式为每月自动发放时 该值代表的是几号 当发放方式为每年自动发放时 该值代表 1每年员工入职日 2每年1月1日", example = "1")
private Integer issueTimeType;
@Schema(description = "发放日期(设置好后 插入发放日期 - 发放完成后插入下一次发放日期) 如果是 null 的话代表手动发放和加班自动计算")
@Schema(description = "发放日期(设置好后 插入发放日期 - 发放完成后插入下一次发放日期) 如果是 null 的话代表手动发放和加班自动计算或者每年员工入职日")
private LocalDateTime issueTime;
@Schema(description = "额度规则 1固定规则 2按工龄 0代表自动发放或者加班自动计算")
@ -38,14 +38,14 @@ public class HolidayBalanceSettingSaveReqVO {
@Schema(description = "是否按实际工作时长发放 0否 1是(例如每年1月1日发放6天假期入职时间是6月1日的员工则按照半年发放3天假期当余额出现小数时按四舍五入取整)")
private Integer actualWorkFlag;
@Schema(description = "有效期类型 1自发放日起1个月 2自发放日起1周年 3按入职日期起12个月 4自然年1月1日-12月31日 5每年固定时间作废 6加班多少天后作废 7永久有效 8每月固定时间作废 9每季末作废")
@Schema(description = "有效期类型 1自发放日起1个月 2自发放日起1周年 3按入职日期起12个月 4自然年1月1日-12月31日 5每年固定时间作废 6永久有效 7每月固定时间作废 8每季末作废")
private Integer validityPeriod;
@Schema(description = "每年固定时间作废格式 MM-dd 例如 09-10 每年9月10号作废", example = "12794")
private String fixedEveryYearInvalid;
@Schema(description = "灵活作废时间 根据有效期类型代表不同意思")
private Integer invalidFlexible;
@Schema(description = "每月固定时间作废 格式 1 or 4 or 7 or 10")
private Integer fixedEveryMonthInvalid;
@Schema(description = "是否允许延长有效期 0否 1是")
private Integer extensionAllowedFlag;

View File

@ -10,6 +10,8 @@ import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingRespVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting.HolidaySettingDO;
import cn.iocoder.yudao.module.system.service.holiday.holidaysetting.HolidaySettingService;
import io.swagger.v3.oas.annotations.Operation;
@ -43,12 +45,6 @@ public class HolidaySettingController {
return success(holidaySettingService.createOrEdit(createReqVO));
}
@PostMapping("/editDetection")
@Operation(summary = "修改检测")
public CommonResult<HolidaySettingEditVO> editDetection(@Valid @RequestBody HolidaySettingSaveReqVO createReqVO) {
return success(holidaySettingService.editDetection(createReqVO));
}
@DeleteMapping("/delete")
@Operation(summary = "删除假期设置")
@Parameter(name = "id", description = "编号", required = true)
@ -65,6 +61,13 @@ public class HolidaySettingController {
return success(vo);
}
@GetMapping("/getAllHolidaySetting")
@Operation(summary = "获取所有假期设置")
public CommonResult<List<HolidaySettingRespVO>> getAllHolidaySetting(@RequestParam Long userId) {
List<HolidaySettingRespVO> vos = holidaySettingService.getAllHolidaySetting(userId);
return success(vos);
}
@GetMapping("/page")
@Operation(summary = "获得假期设置分页")
public CommonResult<PageResult<HolidaySettingRespVO>> getHolidaySettingPage(@Valid HolidaySettingPageReqVO pageReqVO) {

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.dto;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.DetermineHolidayBalanceSettingSwitchVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.PersonnelChangesVO;
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.holidaysettingrange.HolidaySettingRangeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayworkingage.HolidayWorkingAgeDO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import java.util.List;
@Data
@Builder
public class RecalculateAssignedDTO {
@Schema(description = "假期设置")
private HolidaySettingDO holidaySetting;
@Schema(description = "假期余额设置")
private HolidayBalanceSettingDO holidayBalanceSetting;
@Schema(description = "假期额度工龄配置")
private List<HolidayWorkingAgeDO> holidayWorkingAges;
@Schema(description = "人员范围")
private PersonnelChangesVO personnelChangesVO;
@Schema(description = "变动")
private DetermineHolidayBalanceSettingSwitchVO determineHolidayBalanceSettingSwitchVO;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class DetermineHolidayBalanceSettingSwitchVO {
@Schema(description = "开关是否变动 true 是 false 否")
private boolean changeFlag;
@Schema(description = "开关是否开启 true 是 false 否")
private boolean switchFlag;
@Schema(description = "发放方式调整 true 是 false 否")
private boolean adjustTypeFlag;
@Schema(description = "发放日期调整 true 是 false 否")
private boolean dateAdjustFlag;
@Schema(description = "额度规则调整 true 是 false 否")
private boolean quotaRuleFlag;
@Schema(description = "额度调整 true 是 false 否")
private boolean quotaFlag;
}

View File

@ -30,9 +30,6 @@ public class HolidaySettingPageReqVO extends PageParam {
@Schema(description = "请假最小单位 1按天 2按半天 3按小时")
private Integer minUnit;
@Schema(description = "工作时长 小时(一天的工作折算为多少小时)")
private Integer lengthOfWork;
@Schema(description = "请假取整 0否 1是")
private Integer roundFlag;

View File

@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@ -40,9 +41,6 @@ public class HolidaySettingRespVO {
@ExcelProperty("请假最小单位 1按天 2按半天 3按小时")
private Integer minUnit;
@Schema(description = "工作时长 小时(一天的工作折算为多少小时)")
private Integer lengthOfWork;
@Schema(description = "请假取整 0否 1是")
@ExcelProperty("请假取整 0否 1是")
private Integer roundFlag;
@ -71,4 +69,7 @@ public class HolidaySettingRespVO {
@Schema(description = "余额规则 发放方式 1每月自动发放 2每年自动发放 3手动发放 4加班时长自动计入余额 null 表示不限制余额")
private Integer balanceRule;
@Schema(description = "假期余额余额")
private BigDecimal holidayBalance;;
}

View File

@ -30,9 +30,6 @@ public class HolidaySettingSaveReqVO {
@Schema(description = "请假最小单位 1按天 2按半天 3按小时")
private Integer minUnit;
@Schema(description = "工作时长 小时(一天的工作折算为多少小时)")
private Integer lengthOfWork;
@Schema(description = "请假取整 0否 1是")
private Integer roundFlag;

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysettingrange.HolidaySettingRangeDO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class PersonnelChangesVO {
@Schema(description = "原所有人员")
private List<HolidaySettingRangeDO> oldAllList;
@Schema(description = "需要新增的人员范围")
private List<HolidaySettingRangeDO> saveList;
@Schema(description = "需要删除的人员范围")
private List<HolidaySettingRangeDO> delList;
@Schema(description = "现有的人员范围")
private List<HolidaySettingRangeDO> newAllList;
}

View File

@ -9,6 +9,8 @@ import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserRespVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuser.HolidayUserDO;
import cn.iocoder.yudao.module.system.service.holiday.holidayuser.HolidayUserService;
import io.swagger.v3.oas.annotations.Operation;
@ -60,6 +62,14 @@ public class HolidayUserController {
return success(true);
}
@GetMapping("/getHolidayUserDynamic")
@Operation(summary = "获得员工假期动态列表")
public CommonResult<HolidayUserVO> getHolidayUserDynamic(@Valid UserPageReqVO userPageReqVO) {
HolidayUserVO holidayUser = holidayUserService.getHolidayUserDynamic(userPageReqVO);
return success(holidayUser);
}
@GetMapping("/get")
@Operation(summary = "获得员工假期")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@ -82,12 +92,12 @@ public class HolidayUserController {
@PreAuthorize("@ss.hasPermission('system:holiday-user:export')")
@OperateLog(type = EXPORT)
public void exportHolidayUserExcel(@Valid HolidayUserPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<HolidayUserDO> list = holidayUserService.getHolidayUserPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "员工假期.xls", "数据", HolidayUserRespVO.class,
BeanUtils.toBean(list, HolidayUserRespVO.class));
BeanUtils.toBean(list, HolidayUserRespVO.class));
}
}

View File

@ -0,0 +1,13 @@
package cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class HolidayUserMapVO {
@Schema(description = "对应假期规则的id")
private Long id;
@Schema(description = "展示值(假期数量 或者 用户名称等)")
private String value;
}

View File

@ -28,14 +28,6 @@ public class HolidayUserPageReqVO extends PageParam {
@Schema(description = "假期余额(这里的单位根据假期设置的来 没有固定单位)")
private BigDecimal holidayBalance;
@Schema(description = "过期时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expiredTime;
@Schema(description = "过期提醒时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expirationReminderTime;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;

View File

@ -36,14 +36,6 @@ public class HolidayUserRespVO {
@ExcelProperty("假期余额(这里的单位根据假期设置的来 没有固定单位)")
private BigDecimal holidayBalance;
@Schema(description = "过期时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expiredTime;
@Schema(description = "过期提醒时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expirationReminderTime;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;

View File

@ -30,12 +30,4 @@ public class HolidayUserSaveReqVO {
@Schema(description = "假期余额(这里的单位根据假期设置的来 没有固定单位)")
private BigDecimal holidayBalance;
@Schema(description = "过期时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expiredTime;
@Schema(description = "过期提醒时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expirationReminderTime;
}

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Map;
@Data
public class HolidayUserVO {
@Schema(description = "表头")
private Map<Integer, String> headers;
@Schema(description = "列表值")
private PageResult<HolidayUserValuePageVO> page;
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class HolidayUserValuePageVO {
@Schema(description = "用户id", example = "15129")
private Long userId;
@Schema(description = "假期类型列表 key 为下表 value为值(其中有两个对象一个为具体假期的id(可能为null) 一个为当前用户对应假期的余额)", example = "22544")
private Map<Integer, HolidayUserMapVO> listOfHolidayTypes = new HashMap<>();
}

View File

@ -1,31 +1,24 @@
package cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecord;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecord.vo.HolidayUserRecordPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecord.vo.HolidayUserRecordRespVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecord.vo.HolidayUserRecordSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuserrecord.HolidayUserRecordDO;
import cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord.HolidayUserRecordService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 员工假期记录")
@RestController
@ -39,33 +32,16 @@ public class HolidayUserRecordController {
@PostMapping("/create")
@Operation(summary = "创建员工假期记录")
@PreAuthorize("@ss.hasPermission('system:holiday-user-record:create')")
public CommonResult<Long> createHolidayUserRecord(@Valid @RequestBody HolidayUserRecordSaveReqVO createReqVO) {
return success(holidayUserRecordService.createHolidayUserRecord(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新员工假期记录")
@PreAuthorize("@ss.hasPermission('system:holiday-user-record:update')")
public CommonResult<Boolean> updateHolidayUserRecord(@Valid @RequestBody HolidayUserRecordSaveReqVO updateReqVO) {
holidayUserRecordService.updateHolidayUserRecord(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除员工假期记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:holiday-user-record:delete')")
public CommonResult<Boolean> deleteHolidayUserRecord(@RequestParam("id") Long id) {
holidayUserRecordService.deleteHolidayUserRecord(id);
return success(true);
public CommonResult createHolidayUserRecord(@Valid @RequestBody HolidayUserRecordSaveReqVO createReqVO) {
holidayUserRecordService.createHolidayUserRecord(createReqVO);
return success("ok");
}
@GetMapping("/get")
@Operation(summary = "获得员工假期记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:holiday-user-record:query')")
public CommonResult<HolidayUserRecordRespVO> getHolidayUserRecord(@RequestParam("id") Long id) {
HolidayUserRecordDO holidayUserRecord = holidayUserRecordService.getHolidayUserRecord(id);
public CommonResult<List<HolidayUserRecordRespVO>> getHolidayUserRecord(@RequestParam("userId") Long userId,
@RequestParam("holidaySettingId") Long holidaySettingId) {
List<HolidayUserRecordDO> holidayUserRecord = holidayUserRecordService.getHolidayUserRecord(userId, holidaySettingId);
return success(BeanUtils.toBean(holidayUserRecord, HolidayUserRecordRespVO.class));
}
@ -77,17 +53,4 @@ public class HolidayUserRecordController {
return success(BeanUtils.toBean(pageResult, HolidayUserRecordRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出员工假期记录 Excel")
@PreAuthorize("@ss.hasPermission('system:holiday-user-record:export')")
@OperateLog(type = EXPORT)
public void exportHolidayUserRecordExcel(@Valid HolidayUserRecordPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<HolidayUserRecordDO> list = holidayUserRecordService.getHolidayUserRecordPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "员工假期记录.xls", "数据", HolidayUserRecordRespVO.class,
BeanUtils.toBean(list, HolidayUserRecordRespVO.class));
}
}

View File

@ -1,11 +1,13 @@
package cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecord.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import java.math.BigDecimal;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ -34,9 +36,33 @@ public class HolidayUserRecordPageReqVO extends PageParam {
@Schema(description = "假期余额(这里的单位根据假期设置的来 没有固定单位)")
private BigDecimal holidayBalance;
@Schema(description = "发放时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime releaseTime;
@Schema(description = "过期时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expiredTime;
@Schema(description = "过期提醒时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expirationReminderTime;
@Schema(description = "过期是否提醒 0否 1是")
private Integer expirationReminderFlag;
@Schema(description = "剩余余额")
private BigDecimal remainingBalance;
@Schema(description = "过期是否扣减 0否 1是")
private Integer expiredDeductionFlag;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "原因", example = "原因")
private String reason;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;

View File

@ -1,13 +1,15 @@
package cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecord.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.util.*;
import java.math.BigDecimal;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 员工假期记录 Response VO")
@Data
@ -42,10 +44,36 @@ public class HolidayUserRecordRespVO {
@ExcelProperty("假期余额(这里的单位根据假期设置的来 没有固定单位)")
private BigDecimal holidayBalance;
@Schema(description = "发放时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime releaseTime;
@Schema(description = "过期时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expiredTime;
@Schema(description = "过期提醒时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime expirationReminderTime;
@Schema(description = "过期是否提醒 0否 1是")
private Integer expirationReminderFlag;
@Schema(description = "剩余余额")
private BigDecimal remainingBalance;
@Schema(description = "过期是否扣减 0否 1是")
@ExcelProperty("过期是否扣减 0否 1是")
private Integer expiredDeductionFlag;
@Schema(description = "备注", example = "随便")
@ExcelProperty("备注")
private String remark;
@Schema(description = "原因", example = "原因")
@ExcelProperty("原因")
private String reason;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;

View File

@ -2,30 +2,25 @@ package cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecor
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.*;
import javax.validation.constraints.*;
import java.util.*;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 员工假期记录新增/修改 Request VO")
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Data
public class HolidayUserRecordSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2116")
private Long id;
@Schema(description = "用户id", example = "18256")
private Long userId;
@Schema(description = "员工假期id", example = "23298")
private Long holidayUserId;
@Schema(description = "假期设置id", example = "25199")
private Long holidaySettingId;
@Schema(description = "假期余额设置id", example = "20788")
private Long holidayBalanceSettingId;
@Schema(description = "操作方向 0新增 1减去")
private Integer direction;
@ -35,4 +30,6 @@ public class HolidayUserRecordSaveReqVO {
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "原因", example = "原因")
private String reason;
}

View File

@ -9,6 +9,7 @@ import lombok.NoArgsConstructor;
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;
@ -38,4 +39,7 @@ public class UserPageReqVO extends PageParam {
@Schema(description = "部门编号,同时筛选子部门", example = "1024")
private Long deptId;
@Schema(description = "部门ids", example = "1024")
private List<Long> deptIds;
}

View File

@ -0,0 +1,59 @@
package cn.iocoder.yudao.module.system.convert.worklog;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.module.system.api.subscribe.dto.MsgData;
import cn.iocoder.yudao.module.system.api.subscribe.dto.SubscribeMessageReqDTO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Date;
@Mapper
public interface HolidayRemindConvert {
HolidayRemindConvert INSTANCE = Mappers.getMapper(HolidayRemindConvert.class);
/**
* @param openId 微信小程序唯一id
* @param nickname 发布人姓名
* @param miniProgramState 小程序的状态
* @return
*/
default SubscribeMessageReqDTO convertHolidayRemind(String openId, String comment, String nickname, String miniProgramState) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(openId);
message.setTemplateId("fH29xjNb8pe-7onQ-wE3QrBAC-y8aaC_oosYZKNMtzM");
//消息类型
MsgData noticeType = new MsgData();
noticeType.setName("phrase8");
noticeType.setValue("评论回复");
message.addData(noticeType);
//发送人
MsgData publishMan = new MsgData();
publishMan.setName("thing16");
publishMan.setValue(nickname);
message.addData(publishMan);
//发送时间
MsgData createTime = new MsgData();
createTime.setName("time3");
createTime.setValue(DateUtils.dateFormat(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
message.addData(createTime);
//消息内容
MsgData content = new MsgData();
content.setName("thing2");
if (comment.length() > 10) {
comment = comment.substring(0, 10) + ". . . . ";
}
content.setValue(comment);
message.addData(content);
message.setMiniprogramState(miniProgramState);
// message.setPage("/subPages/workLogDetail/workLogDetail?id=" + logCommentDO.getWorkLogId());
return message;
}
}

View File

@ -48,6 +48,18 @@ public class AttendanceGroupShiftItemDO extends BaseDO {
* 结束打卡时间 HH:mm
*/
private String endTime;
/**
* 是否开启中间时间段休息 0否 1是
*/
private Integer restFlag;
/**
* 休息开始时间 HH:mm
*/
private String restBeginTime;
/**
* 休息结束时间 HH:mm
*/
private String restEndTime;
/**
* 是否必须 0否 1是 (如果不是必须系统会自动打卡)
*/
@ -73,4 +85,4 @@ public class AttendanceGroupShiftItemDO extends BaseDO {
*/
private Integer afterPunchTimeDownWork;
}
}

View File

@ -41,11 +41,11 @@ public class HolidayBalanceSettingDO extends BaseDO {
*/
private Integer type;
/**
* 发放日期 1每月n日 2每年员工入职日 3每年1月1日
* 发放日期 当发放方式为每月自动发放时 该值代表的是几号 当发放方式为每年自动发放时 该值代表 1每年员工入职日 2每年1月1日
*/
private Integer issueTimeType;
/**
* 发放日期(设置好后 插入发放日期 - 发放完成后插入下一次发放日期) 如果是 null 的话代表手动发放和加班自动计算
* 发放日期(设置好后 插入发放日期 - 发放完成后插入下一次发放日期) 如果是 null 的话代表手动发放和加班自动计算或者每年员工入职日或者每年员工入职日
*/
private LocalDateTime issueTime;
/**
@ -61,7 +61,7 @@ public class HolidayBalanceSettingDO extends BaseDO {
*/
private Integer actualWorkFlag;
/**
* 有效期类型 1自发放日起1个月 2自发放日起1周年 3按入职日期起12个月 4自然年1月1日-12月31日 5每年固定时间作废 6加班多少天后作废 7永久有效 8每月固定时间作废 9每季末作废
* 有效期类型 1自发放日起1个月 2自发放日起1周年 3按入职日期起12个月 4自然年1月1日-12月31日 5每年固定时间作废 6永久有效 7每月固定时间作废 8每季末作废
*/
private Integer validityPeriod;
/**
@ -69,9 +69,9 @@ public class HolidayBalanceSettingDO extends BaseDO {
*/
private String fixedEveryYearInvalid;
/**
* 灵活作废时间 根据有效期类型代表不同意思
* 每月固定时间作废 格式 1 or 4 or 7 or 10
*/
private Integer invalidFlexible;
private Integer fixedEveryMonthInvalid;
/**
* 是否允许延长有效期 0否 1是
*/

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaybalancesetting.HolidayBalanceSettingDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
@ -48,10 +49,6 @@ public class HolidaySettingDO extends BaseDO {
* 请假最小单位 1按天 2按半天 3按小时
*/
private Integer minUnit;
/**
* 工作时长 小时(一天的工作折算为多少小时)
*/
private Integer lengthOfWork;
/**
* 请假取整 0否 1是
*/
@ -74,4 +71,10 @@ public class HolidaySettingDO extends BaseDO {
*/
@TableField(exist = false)
private Integer balanceRule;
/**
* 假期余额设置
*/
@TableField(exist = false)
private HolidayBalanceSettingDO holidayBalanceSettingDO;
}

View File

@ -46,14 +46,6 @@ public class HolidayUserDO extends BaseDO {
* 假期余额(这里的单位根据假期设置的来 没有固定单位)
*/
private BigDecimal holidayBalance;
/**
* 过期时间
*/
private LocalDateTime expiredTime;
/**
* 过期提醒时间
*/
private LocalDateTime expirationReminderTime;
public HolidayUserDO(Long id, Long userId, Long holidaySettingId, Long holidayBalanceSettingId) {
this.id = id;
@ -61,7 +53,5 @@ public class HolidayUserDO extends BaseDO {
this.holidaySettingId = holidaySettingId;
this.holidayBalanceSettingId = holidayBalanceSettingId;
this.holidayBalance = BigDecimal.ZERO;
this.expiredTime = null;
this.expirationReminderTime = null;
}
}

View File

@ -1,12 +1,13 @@
package cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuserrecord;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 员工假期记录 DO
@ -52,9 +53,39 @@ public class HolidayUserRecordDO extends BaseDO {
* 假期余额(这里的单位根据假期设置的来 没有固定单位)
*/
private BigDecimal holidayBalance;
/**
* 发放时间
*/
private LocalDateTime releaseTime;
/**
* 过期时间
*/
private LocalDateTime expiredTime;
/**
* 过期提醒时间
*/
private LocalDateTime expirationReminderTime;
/**
* 过期是否提醒 0否 1是
*/
private Integer expirationReminderFlag;
/**
* 剩余余额
*/
private BigDecimal remainingBalance;
/**
* 过期是否扣减 0否 1是
*/
private Integer expiredDeductionFlag;
/**
* 备注
*/
private String remark;
/**
* 原因
*/
private String reason;
}

View File

@ -153,4 +153,7 @@ public class AdminUserDO extends TenantBaseDO {
* 微信小程序openId
*/
private String openId;
@TableField(exist = false)
private String deptName;
}

View File

@ -21,5 +21,4 @@ public interface AttendanceGroupShiftMapper extends BaseMapperX<AttendanceGroupS
.betweenIfPresent(AttendanceGroupShiftDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(AttendanceGroupShiftDO::getId));
}
}
}

View File

@ -27,7 +27,7 @@ public interface HolidayBalanceSettingMapper extends BaseMapperX<HolidayBalanceS
.eqIfPresent(HolidayBalanceSettingDO::getActualWorkFlag, reqVO.getActualWorkFlag())
.eqIfPresent(HolidayBalanceSettingDO::getValidityPeriod, reqVO.getValidityPeriod())
.eqIfPresent(HolidayBalanceSettingDO::getFixedEveryYearInvalid, reqVO.getFixedEveryYearInvalid())
.eqIfPresent(HolidayBalanceSettingDO::getInvalidFlexible, reqVO.getInvalidFlexible())
.eqIfPresent(HolidayBalanceSettingDO::getFixedEveryMonthInvalid, reqVO.getFixedEveryMonthInvalid())
.eqIfPresent(HolidayBalanceSettingDO::getExtensionAllowedFlag, reqVO.getExtensionAllowedFlag())
.eqIfPresent(HolidayBalanceSettingDO::getExtendNum, reqVO.getExtendNum())
.eqIfPresent(HolidayBalanceSettingDO::getExpirationReminderFlag, reqVO.getExpirationReminderFlag())

View File

@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.system.dal.mysql.holiday.holidayuser;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuser.HolidayUserDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Mapper;
/**
@ -25,4 +27,12 @@ public interface HolidayUserMapper extends BaseMapperX<HolidayUserDO> {
.orderByDesc(HolidayUserDO::getId));
}
/**
* 获取分页列表
*
* @param pageReqVO
* @param objectPage
* @return
*/
IPage<HolidayUserDO> getPageList(HolidayUserPageReqVO pageReqVO, Page<Object> objectPage);
}

View File

@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSimpleRe
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@ -175,4 +176,12 @@ public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
* @return
*/
List<AdminUserDO> getAllList(@Param("dto") UserDTO dto);
/**
* 获取
*
* @param vo
* @return
*/
IPage<AdminUserDO> getUserBringDeptPage(@Param("page") Page page, @Param("vo") UserPageReqVO vo);
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.system.job.holiday;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuserrecord.HolidayUserRecordDO;
import cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord.HolidayUserRecordService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
@Component
@Slf4j
public class HolidayBeOverdueJob {
@Resource
private HolidayUserRecordService holidayUserRecordService;
@XxlJob("holidayBeOverdueJob")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
public ReturnT<String> execute() throws Exception {
// -- 发放假期定时任务 - 每天凌晨3点执行一次 判断下是不是该发放了
log.info("开始 假期过期扣减");
// -- 先获取所有假期余额设置
LocalDateTime now = LocalDateTime.now();
//获取假期过期的对象
List<HolidayUserRecordDO> list = holidayUserRecordService.getHolidayBeOverdue(now);
holidayUserRecordService.beOverdue(list);
log.info("结束 假期过期扣减");
// 返回执行成功
return ReturnT.SUCCESS;
}
}

View File

@ -0,0 +1,114 @@
package cn.iocoder.yudao.module.system.job.holiday;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
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.holidaysettingrange.HolidaySettingRangeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayworkingage.HolidayWorkingAgeDO;
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 com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
@Slf4j
public class HolidayGrantJob {
// TODO: 2024/4/22 - 每十分钟执行一次 将漏打卡的设为缺卡 这里的update要保证命中索引 保证是行锁 不然容易导致锁表
@Resource
private HolidayBalanceSettingService holidayBalanceSettingService;
@Resource
private HolidaySettingService holidaySettingService;
@Resource
private HolidayUserRecordService holidayUserRecordService;
@Resource
private HolidaySettingRangeService holidaySettingRangeService;
@Resource
private HolidayWorkingAgeService holidayWorkingAgeService;
@XxlJob("holidayGrantJob")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
public ReturnT<String> execute() throws Exception {
// -- 发放假期定时任务 - 每天凌晨3点执行一次 判断下是不是该发放了
log.info("开始 发放假期");
// -- 先获取所有假期余额设置
LocalDateTime now = LocalDateTime.now();
List<HolidayBalanceSettingDO> list = holidayBalanceSettingService.list(new LambdaQueryWrapper<HolidayBalanceSettingDO>()
.eq(HolidayBalanceSettingDO::getStatus, 1)
.in(HolidayBalanceSettingDO::getType, Arrays.asList(1, 2)));
if (CollectionUtil.isEmpty(list)) {
log.info("结束 发放假期");
return ReturnT.SUCCESS;
}
List<Long> holidaySettingIds = list.stream().map(HolidayBalanceSettingDO::getHolidaySettingId).collect(Collectors.toList());
List<HolidaySettingDO> holidaySettingDOS = holidaySettingService.listByIds(holidaySettingIds);
Map<Long, HolidaySettingDO> holidaySettingMap = holidaySettingDOS.stream().collect(Collectors.toMap(HolidaySettingDO::getId, holidaySettingDO -> holidaySettingDO));
List<HolidaySettingRangeDO> holidaySettingRangeDOS = holidaySettingRangeService.getListByHolidaySettingIds(holidaySettingIds);
Map<Long, List<HolidaySettingRangeDO>> holidaySettingRangeMap = holidaySettingRangeDOS.stream().collect(Collectors.groupingBy(HolidaySettingRangeDO::getHolidaySettingId, Collectors.toList()));
List<HolidayWorkingAgeDO> holidayWorkingAgeDOS = holidayWorkingAgeService.selectBySettingIds(holidaySettingIds);
Map<Long, List<HolidayWorkingAgeDO>> holidayWorkingAgeDOMap = holidayWorkingAgeDOS.stream().collect(Collectors.groupingBy(HolidayWorkingAgeDO::getHolidaySettingId, Collectors.toList()));
List<HolidayBalanceSettingDO> editList = new ArrayList<>();
// -- 过滤出 按月发放 or 按每年一月一号 发放 的并且时间到了的
List<HolidayBalanceSettingDO> fixedGrantList = list.stream().filter(holidayBalanceSettingDO ->
(holidayBalanceSettingDO.getType() == 1 || (holidayBalanceSettingDO.getType() == 2 && holidayBalanceSettingDO.getIssueTimeType() == 2))
&& holidayBalanceSettingDO.getIssueTime() != null
&& holidayBalanceSettingDO.getIssueTime().isBefore(now)).collect(Collectors.toList());
if (CollectionUtil.isEmpty(fixedGrantList)) {
for (HolidayBalanceSettingDO holidayBalanceSettingDO : fixedGrantList) {
// 计算下一次发放日期
LocalDateTime issueTime = holidaySettingService.calculateNextReleaseDate(now, holidayBalanceSettingDO);
holidayBalanceSettingDO.setIssueTime(issueTime);
editList.add(holidayBalanceSettingDO);
Long holidaySettingId = holidayBalanceSettingDO.getHolidaySettingId();
// 发放假期
holidayUserRecordService.grant(holidaySettingMap.get(holidaySettingId), holidaySettingRangeMap.get(holidaySettingId), holidayBalanceSettingDO, holidayWorkingAgeDOMap.get(holidaySettingId));
}
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

@ -0,0 +1,157 @@
package cn.iocoder.yudao.module.system.job.holiday;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
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.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.job.holiday.dto.HolidayRemindDTO;
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.holidayuserrecord.HolidayUserRecordService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Component
@Slf4j
public class HolidayRemindJob {
// TODO: 2024/4/22 - 每十分钟执行一次 将漏打卡的设为缺卡 这里的update要保证命中索引 保证是行锁 不然容易导致锁表
@Resource
private HolidayBalanceSettingService holidayBalanceSettingService;
@Resource
private HolidaySettingService holidaySettingService;
@Resource
private HolidayUserRecordService holidayUserRecordService;
@Resource
private AdminUserService adminUserService;
@Resource
private DeptService deptService;
@Resource
private SubscribeMessageSendApi subscribeMessageSendApi;
@XxlJob("holidayRemindJob")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
public ReturnT<String> execute() throws Exception {
// -- 发放假期定时任务 - 每天凌晨3点执行一次 判断下是不是该发放了
log.info("开始 过期提醒");
// -- 先获取所有假期余额设置
LocalDateTime now = LocalDateTime.now();
// 获取用户假期记录 中需要提醒的数据
List<HolidayUserRecordDO> list = holidayUserRecordService.getHolidayRemind(now);
List<Long> userIds = new ArrayList<>();
Map<Long, List<HolidayUserRecordDO>> recordMap = new HashMap<>();
List<Long> holidayBalanceSettingIds = new ArrayList<>();
if (CollectionUtil.isNotEmpty(list)) {
userIds = list.stream().map(HolidayUserRecordDO::getUserId).distinct().collect(Collectors.toList());
recordMap = list.stream().collect(Collectors.groupingBy(HolidayUserRecordDO::getHolidayBalanceSettingId));
holidayBalanceSettingIds = list.stream().map(HolidayUserRecordDO::getHolidayBalanceSettingId).distinct().collect(Collectors.toList());
}
List<AdminUserDO> userList = new ArrayList<>();
List<Long> deptIds = new ArrayList<>();
if (CollectionUtil.isNotEmpty(userIds)) {
userList = adminUserService.getAllList(new UserDTO().setUserIds(userIds));
}
if (CollectionUtil.isNotEmpty(userList)) {
deptIds = userList.stream().map(AdminUserDO::getDeptId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
}
List<DeptDO> deptDOS = new ArrayList<>();
if (CollectionUtil.isNotEmpty(deptIds)) {
deptDOS = deptService.getDeptList(deptIds);
}
List<Long> leaderUserIds = new ArrayList<>();
if (CollectionUtil.isNotEmpty(deptDOS)) {
// -- 查询主管
leaderUserIds = deptDOS.stream().map(DeptDO::getLeaderUserId).distinct().collect(Collectors.toList());
}
if (CollectionUtil.isNotEmpty(leaderUserIds)) {
List<AdminUserDO> executiveDirectorUsers = adminUserService.getAllList(new UserDTO().setUserIds(leaderUserIds));
userList.addAll(executiveDirectorUsers);
}
Map<Long, AdminUserDO> userMap = userList.stream().distinct().collect(Collectors.toMap(AdminUserDO::getId, adminUserDO -> adminUserDO));
Map<Long, AdminUserDO> leaderMap = new HashMap<>();
for (DeptDO deptDO : deptDOS) {
leaderMap.put(deptDO.getId(), userMap.get(deptDO.getLeaderUserId()));
}
List<HolidayBalanceSettingDO> holidayBalanceSettingDOS = new ArrayList<>();
List<HolidaySettingDO> holidaySettingDOS = new ArrayList<>();
if (CollectionUtil.isNotEmpty(holidayBalanceSettingIds)) {
holidayBalanceSettingDOS = holidayBalanceSettingService.getByIds(holidayBalanceSettingIds);
holidaySettingDOS = holidaySettingService.listByIds(holidayBalanceSettingIds);
}
// 获取到假期余额设置 为了获取发送范围
Map<Long, HolidaySettingDO> holidaySettingMap = holidaySettingDOS.stream().collect(Collectors.toMap(HolidaySettingDO::getId, holidaySettingDO -> holidaySettingDO));
List<HolidayRemindDTO> holidayRemindDTOS = new ArrayList<>();
for (HolidayBalanceSettingDO holidayBalanceSettingDO : holidayBalanceSettingDOS) {
List<HolidayUserRecordDO> holidayUserRecordDOS = recordMap.get(holidayBalanceSettingDO.getId());
for (HolidayUserRecordDO holidayUserRecordDO : holidayUserRecordDOS) {
HolidayRemindDTO remindDTO = new HolidayRemindDTO();
AdminUserDO user = userMap.get(holidayUserRecordDO.getUserId());
if (user == null || user.getOpenId() == null) {
continue;
}
String name = holidaySettingMap.get(holidayBalanceSettingDO.getHolidaySettingId()) == null ? "" : holidaySettingMap.get(holidayBalanceSettingDO.getHolidaySettingId()).getName();
if (holidayBalanceSettingDO.getReminderRange() == 1) {
remindDTO.setUserId(holidayUserRecordDO.getUserId());
remindDTO.setOpenId(user.getOpenId());
remindDTO.setMsg("您的" + name + "假期即将过期");
holidayRemindDTOS.add(remindDTO);
} else if (holidayBalanceSettingDO.getReminderRange() == 2) {
// 获取到主管 - 这里获取主管需要查询到对应用户所在的部门 - 完了后 在获取部门中的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);
} else {
remindDTO.setUserId(holidayUserRecordDO.getUserId());
remindDTO.setOpenId(user.getOpenId());
remindDTO.setMsg("您的" + name + "假期即将过期");
holidayRemindDTOS.add(remindDTO);
// 获取到主管 - 这里获取主管需要查询到对应用户所在的部门 - 完了后 在获取部门中的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);
}
}
}
holidayRemindDTOS = holidayRemindDTOS.stream().distinct().filter(a -> a.getOpenId() != null).collect(Collectors.toList());
// 发送信息 -
for (HolidayRemindDTO holidayRemindDTO : holidayRemindDTOS) {
try {
subscribeMessageSendApi.sendWorkLogComment(HolidayRemindConvert.INSTANCE.convertHolidayRemind(
holidayRemindDTO.getOpenId(), holidayRemindDTO.getMsg(), userMap.get(holidayRemindDTO.getUserId()).getNickname(),
"formal"));
} catch (Exception e) {
log.error("发送假期过期提醒失败:{}", holidayRemindDTO);
}
}
holidayUserRecordService.editReminder(list);
if (CollectionUtil.isEmpty(list)) {
log.info("结束 过期提醒");
return ReturnT.SUCCESS;
}
log.info("结束 过期提醒");
// 返回执行成功
return ReturnT.SUCCESS;
}
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.system.job.holiday.dto;
import lombok.Data;
@Data
public class HolidayRemindDTO {
/**
* 用户id
*/
private Long userId;
/**
* 用户openId
*/
private String openId;
/**
* 消息内容
*/
private String msg;
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.system.service.attendance;
import cn.hutool.json.JSONObject;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendanceTimeRangeInfoDTO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceTimeRangeInfoVO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.dto.*;
import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.addressgroup.AttendanceAddressGroupItemDO;
@ -160,4 +162,12 @@ public interface AttendanceService {
* @return
*/
JSONObject attendanceMachineCheck(JSONObject object);
/**
* 按时间范围获取用户当前范围考勤信息
*
* @param attendanceTimeRangeInfoDTO
* @return
*/
Map<String, AttendanceTimeRangeInfoVO> getAttendanceInfoByTimeRange(AttendanceTimeRangeInfoDTO attendanceTimeRangeInfoDTO);
}

View File

@ -15,6 +15,8 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.distance.GeoUtil;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendanceTimeRangeInfoDTO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceTimeRangeInfoVO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.dto.*;
import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.*;
import cn.iocoder.yudao.module.system.controller.admin.punchrecord.vo.AttendancePunchRecordSaveReqVO;
@ -1112,6 +1114,22 @@ public class AttendanceServiceImpl implements AttendanceService {
}
}
@Override
public Map<String, AttendanceTimeRangeInfoVO> getAttendanceInfoByTimeRange(AttendanceTimeRangeInfoDTO dto) {
//获取当前登录用户所在群组
AttendanceGroupDO activationGroup = attendanceGroupService.getByUserId(dto.getUserId());
//不在考勤组
List<String> list = DateUtils.betweenDayList(dto.getStartTime(), dto.getEndTime());
// -- 如果没有考勤组则直接返回 默认对象
if (activationGroup == null) {
return list.stream().collect(Collectors.toMap(Function.identity(), k -> new AttendanceTimeRangeInfoVO()));
}
// 策略模式 - 将不同考勤类型的 分散开逻辑 - 后续好拓展
PunchService punchService = punchHandler.getResource(AttendanceGroupDO.getCodeByType(activationGroup.getType()));
return punchService.getAttendanceInfoByTimeRange(dto.setGroupId(activationGroup.getId())
.setAutoHolidaysFlag(activationGroup.getAutoHolidaysFlag()).setTimes(list));
}
@Override
public void useReplacementCardNum(Long userId) {
userId = userId == null ? getLoginUserId() : userId;

View File

@ -2,10 +2,14 @@ package cn.iocoder.yudao.module.system.service.attendance.fixed;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.iocoder.yudao.framework.common.Constants;
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.AttendanceTimeRangeInfoDTO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceGroupShiftItemVO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceTimeRangeInfoVO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.dto.AttendancePunchPageDTO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendancePunchPageVO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendanceRulesVO;
@ -19,11 +23,11 @@ import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupshiftitem.A
import cn.iocoder.yudao.module.system.dal.mysql.attendance.fixed.AttendanceFixedMapper;
import cn.iocoder.yudao.module.system.service.attendance.AttendanceService;
import cn.iocoder.yudao.module.system.service.attendance.groupshift.AttendanceGroupShiftService;
import cn.iocoder.yudao.module.system.service.attendance.groupshiftitem.AttendanceGroupShiftItemService;
import cn.iocoder.yudao.module.system.service.attendance.punch.PunchService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@ -53,7 +57,7 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch
@Resource
private AttendanceGroupShiftService attendanceGroupShiftService;
@Resource
private StringRedisTemplate stringRedisTemplate;
private AttendanceGroupShiftItemService attendanceGroupShiftItemService;
@Override
@Transactional(rollbackFor = Exception.class)
@ -278,4 +282,36 @@ public class AttendanceFixedServiceImpl implements AttendanceFixedService, Punch
return rules;
}
@Override
public Map<String, AttendanceTimeRangeInfoVO> getAttendanceInfoByTimeRange(AttendanceTimeRangeInfoDTO dto) {
Map<String, AttendanceTimeRangeInfoVO> map = new HashMap<>();
//不在考勤组
for (String time : dto.getTimes()) {
AttendanceTimeRangeInfoVO attendanceTimeRangeInfoVO = new AttendanceTimeRangeInfoVO();
// -- 判断是否根据节假日自动排班 - 如果是的话 - 根据排班的来
LocalDateTime localDateTime = LocalDateTimeUtil.parseDate(time, Constants.REPO_DATE_FORMAT).atStartOfDay();
Boolean isHolidayFlag = Constants.TRUE.equals(dto.getAutoHolidaysFlag()) ?
attendanceService.isHoliday(localDateTime) : null;
// -- 当前是节假日 并且是放假
if (isHolidayFlag != null && isHolidayFlag) {
map.put(time, attendanceTimeRangeInfoVO);
continue;
}
//获取到当天是周几 - 如果是节假日补班的话 - 班次日期就是8
int week = isHolidayFlag != null ? 8 : localDateTime.getDayOfWeek().getValue();
AttendanceFixedDO attendanceFixedDO = this.getByGroupIdAndWeek(dto.getGroupId(), week);
// -- 当前没有班次 - 不需要考勤
if (attendanceFixedDO == null || attendanceFixedDO.getAttendanceGroupShiftId() == null) {
map.put(time, attendanceTimeRangeInfoVO);
continue;
}
List<AttendanceGroupShiftItemDO> attendanceGroupShiftItemDOList = attendanceGroupShiftItemService.getGroupShiftItemListByShiftId(attendanceFixedDO.getAttendanceGroupShiftId());
if (CollectionUtil.isNotEmpty(attendanceGroupShiftItemDOList)) {
List<AttendanceGroupShiftItemVO> items = BeanUtil.copyToList(attendanceGroupShiftItemDOList, AttendanceGroupShiftItemVO.class);
map.put(time, attendanceTimeRangeInfoVO.setNeedAttendance(1).setItems(items));
}
}
return map;
}
}

View File

@ -1,10 +1,13 @@
package cn.iocoder.yudao.module.system.service.attendance.punch;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendanceTimeRangeInfoDTO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceTimeRangeInfoVO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.dto.AttendancePunchPageDTO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendancePunchPageVO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendanceRulesVO;
import java.util.List;
import java.util.Map;
/**
* 打卡 Service 接口
@ -28,4 +31,11 @@ public interface PunchService {
* @return
*/
List<AttendanceRulesVO.WorkRules> getRule(Long attendanceGroupId);
}
/**
*
* @param dto
* @return
*/
Map<String, AttendanceTimeRangeInfoVO> getAttendanceInfoByTimeRange(AttendanceTimeRangeInfoDTO dto);
}

View File

@ -74,6 +74,7 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
@Resource
private AttendanceGroupMapper attendanceGroupMapper;
@Resource
@Lazy
private AdminUserService adminUserService;
// @Resource
// private BpmOALeaveApi bpmOALeaveApi;
@ -326,8 +327,7 @@ public class AttendancePunchRecordServiceImpl implements AttendancePunchRecordSe
public void askingForLeaveAfterwardsToModifyAttendance(AttendancePunchRecordDTO dto) {
punchRecordMapper.update(new AttendancePunchRecordDO()
.setStatus(AttendanceOnTheDayDTO.ASK_FOR_LEAVE)
.setLeaveId(dto.getLeaveId())
.setLeaveType(dto.getLeaveType()),
.setLeaveId(dto.getLeaveId()),
new LambdaUpdateWrapper<AttendancePunchRecordDO>().eq(AttendancePunchRecordDO::getUserId, dto.getUserId())
.ge(AttendancePunchRecordDO::getShouldPunchTime, dto.getStartTime())
.le(AttendancePunchRecordDO::getShouldPunchTime, dto.getEndTime()));

View File

@ -2,10 +2,14 @@ package cn.iocoder.yudao.module.system.service.attendance.scheduling;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.attendance.dto.AttendanceTimeRangeInfoDTO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceGroupShiftItemVO;
import cn.iocoder.yudao.module.system.api.attendance.vo.AttendanceTimeRangeInfoVO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.dto.AttendancePunchPageDTO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendancePunchPageVO;
import cn.iocoder.yudao.module.system.controller.admin.attendance.vo.AttendanceRulesVO;
@ -19,6 +23,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.attendance.scheduling.Atten
import cn.iocoder.yudao.module.system.dal.mysql.attendance.scheduling.AttendanceSchedulingMapper;
import cn.iocoder.yudao.module.system.service.attendance.AttendanceService;
import cn.iocoder.yudao.module.system.service.attendance.groupshift.AttendanceGroupShiftService;
import cn.iocoder.yudao.module.system.service.attendance.groupshiftitem.AttendanceGroupShiftItemService;
import cn.iocoder.yudao.module.system.service.attendance.punch.PunchService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.context.annotation.Lazy;
@ -29,6 +34,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
@ -53,6 +59,8 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ
@Resource
@Lazy
private AttendanceService attendanceService;
@Resource
private AttendanceGroupShiftItemService attendanceGroupShiftItemService;
@Override
@Transactional(rollbackFor = Exception.class)
@ -215,13 +223,7 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ
AttendanceGroupDO activationGroup = dto.getActivationGroup();
vo.setActivationGroup(activationGroup);
//获取到当天是第几天
String schedulingKey = Constants.SCHEDULING + Constants.UNDERLINE + activationGroup.getId();
String indexDayObj = stringRedisTemplate.opsForValue().get(schedulingKey);
if (StrUtil.isEmpty(indexDayObj)) {
// 当作第一天来
indexDayObj = Constants.ONE_STR;
}
Integer indexDay = Integer.valueOf(indexDayObj);
Integer indexDay = this.schedulingAttendanceIndexDayByGroupId(activationGroup.getId());
AttendanceSchedulingDO attendanceSchedulingDO = this.getSchedulingByIndexDay(activationGroup.getId(), indexDay);
// -- 当前没有班次 - 不需要考勤
if (attendanceSchedulingDO == null || Constants.ONE.equals(attendanceSchedulingDO.getRestFlag()) || attendanceSchedulingDO.getAttendanceGroupShiftId() == null) {
@ -234,6 +236,23 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ
return vo;
}
/**
* 通过groupId获取到当天是第几天
*
* @param groupId
* @return
*/
private Integer schedulingAttendanceIndexDayByGroupId(Long groupId) {
String schedulingKey = Constants.SCHEDULING + Constants.UNDERLINE + groupId;
String indexDayObj = stringRedisTemplate.opsForValue().get(schedulingKey);
if (StrUtil.isEmpty(indexDayObj)) {
// 当作第一天来
indexDayObj = Constants.ONE_STR;
}
return Integer.valueOf(indexDayObj);
}
@Override
public List<AttendanceRulesVO.WorkRules> getRule(Long attendanceGroupId) {
List<AttendanceSchedulingDO> list = this.getSchedulingByGroupId(attendanceGroupId);
@ -270,4 +289,76 @@ public class AttendanceSchedulingServiceImpl implements AttendanceSchedulingServ
return rules;
}
}
@Override
public Map<String, AttendanceTimeRangeInfoVO> getAttendanceInfoByTimeRange(AttendanceTimeRangeInfoDTO dto) {
Map<String, AttendanceTimeRangeInfoVO> map = new HashMap<>();
// -- 获取到当前考勤组在第几天 - 完了后再计算下 请假开始时间离当天有多少天 - 然后计算出请假的时间是第几天 再拿到对应天的考勤班次
Integer indexDay = this.schedulingAttendanceIndexDayByGroupId(dto.getGroupId());
LocalDateTime today = LocalDateTime.now();
// -- 获取到请假开始时间离当天有多少天 - 先将两个时间转为一天的开始时间 这样计算准确
long betweenDayNum = LocalDateTimeUtil.between(LocalDateTimeUtil.beginOfDay(today), LocalDateTimeUtil.beginOfDay(dto.getStartTime()), ChronoUnit.DAYS);
// -- 再获取到一共有多少天再循环
Long dayNum = schedulingMapper.selectCount(new LambdaQueryWrapper<AttendanceSchedulingDO>().eq(AttendanceSchedulingDO::getAttendanceGroupId, dto.getGroupId()));
// -- 获取到请假开始时间离当天有多少天
long l = indexDay + betweenDayNum;
if (l > dayNum) {
l = (l - dayNum) % dayNum == 0 ? dayNum : (l - dayNum) % dayNum;
} else if (l < 1) {
l = l % dayNum + dayNum;
}
// -- 开始请假天
int beginTimeDay = (int) l;
//不在考勤组
for (String time : dto.getTimes()) {
// -- 如果超出最大天则按第一天开始算
if (beginTimeDay > dayNum) {
beginTimeDay = 1;
}
AttendanceTimeRangeInfoVO attendanceTimeRangeInfoVO = new AttendanceTimeRangeInfoVO();
// -- 判断是否根据节假日自动排班 - 如果是的话 - 根据排班的来
LocalDateTime localDateTime = LocalDateTimeUtil.parseDate(time, Constants.REPO_DATE_FORMAT).atStartOfDay();
Boolean isHolidayFlag = Constants.TRUE.equals(dto.getAutoHolidaysFlag()) ?
attendanceService.isHoliday(localDateTime) : null;
// -- 当前是节假日 并且是放假
if (isHolidayFlag != null && isHolidayFlag) {
map.put(time, attendanceTimeRangeInfoVO);
continue;
}
AttendanceSchedulingDO attendanceSchedulingDO = this.getSchedulingByIndexDay(dto.getGroupId(), beginTimeDay);
// -- 当前没有班次 - 不需要考勤
if (attendanceSchedulingDO == null || Constants.ONE.equals(attendanceSchedulingDO.getRestFlag()) || attendanceSchedulingDO.getAttendanceGroupShiftId() == null) {
map.put(time, attendanceTimeRangeInfoVO);
continue;
}
List<AttendanceGroupShiftItemDO> attendanceGroupShiftItemDOList = attendanceGroupShiftItemService.getGroupShiftItemListByShiftId(attendanceSchedulingDO.getAttendanceGroupShiftId());
if (CollectionUtil.isNotEmpty(attendanceGroupShiftItemDOList)) {
List<AttendanceGroupShiftItemVO> items = BeanUtil.copyToList(attendanceGroupShiftItemDOList, AttendanceGroupShiftItemVO.class);
map.put(time, attendanceTimeRangeInfoVO.setNeedAttendance(1).setItems(items));
}
beginTimeDay++;
}
return map;
}
// public static void main(String[] args) {
// LocalDateTime today = LocalDateTime.of(2024, 10, 1, 0, 0, 0);
// LocalDateTime start = LocalDateTime.of(2024, 10, 21, 0, 0, 0);
// // -- 获取到请假开始时间离当天有多少天
// long betweenDayNum = LocalDateTimeUtil.between(today, start, ChronoUnit.DAYS);
// // -- 再获取到一共有多少天再循环
// long dayNum = 10L;
// int indexDay = 1;
// long l = indexDay + betweenDayNum;
// if (l > dayNum) {
// l = (l - dayNum) % dayNum == 0 ? dayNum : (l - dayNum) % dayNum;
// } else if (l < 1) {
// l = l % dayNum + dayNum;
// }
// // -- 开始请假天
// int beginTimeDay = (int) l;
// System.out.println(beginTimeDay);
// }
}

View File

@ -1,11 +1,14 @@
package cn.iocoder.yudao.module.system.service.holiday.holidaybalancesetting;
import javax.validation.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaybalancesetting.vo.HolidayBalanceSettingPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaybalancesetting.vo.HolidayBalanceSettingSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaybalancesetting.HolidayBalanceSettingDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* 假期余额设置 Service 接口
@ -54,8 +57,46 @@ public interface HolidayBalanceSettingService {
/**
* 通过及其设置id查询假期余额设置
*
* @param settingId
* @return
*/
HolidayBalanceSettingDO selectBySettingId(Long settingId);
/**
* 通过及其设置ids查询假期余额设置
*
* @param settingIds
* @return
*/
Map<Long, HolidayBalanceSettingDO> selectBySettingIds(List<Long> settingIds);
/**
* 通过假期设置ids获取假期余额设置列表
*
* @param holidaySettingIds
* @return
*/
List<HolidayBalanceSettingDO> getHolidayBalanceSettingByHolidaySettingIds(List<Long> holidaySettingIds);
/**
* 获取假期余额设置
*
* @return
*/
List<HolidayBalanceSettingDO> list(LambdaQueryWrapper<HolidayBalanceSettingDO> lambdaQueryWrapper);
/**
* 批量更新
*
* @param editList
*/
void batchUpdate(List<HolidayBalanceSettingDO> editList);
/**
* 根据ids获取
* @param holidayBalanceSettingIds
* @return
*/
List<HolidayBalanceSettingDO> getByIds(List<Long> holidayBalanceSettingIds);
}

View File

@ -1,5 +1,8 @@
package cn.iocoder.yudao.module.system.service.holiday.holidaybalancesetting;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaybalancesetting.vo.HolidayBalanceSettingPageReqVO;
@ -12,6 +15,8 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 假期余额设置 Service 实现类
@ -68,4 +73,38 @@ public class HolidayBalanceSettingServiceImpl implements HolidayBalanceSettingSe
return null;
}
@Override
public Map<Long, HolidayBalanceSettingDO> selectBySettingIds(List<Long> settingIds) {
if (CollUtil.isEmpty(settingIds)) {
return MapUtil.empty();
}
List<HolidayBalanceSettingDO> list = holidayBalanceSettingMapper.selectList(new LambdaQueryWrapper<HolidayBalanceSettingDO>()
.in(HolidayBalanceSettingDO::getHolidaySettingId, settingIds));
return list.stream().collect(Collectors.toMap(HolidayBalanceSettingDO::getHolidaySettingId, holidayBalanceSettingDO -> holidayBalanceSettingDO));
}
@Override
public List<HolidayBalanceSettingDO> getHolidayBalanceSettingByHolidaySettingIds(List<Long> holidaySettingIds) {
if (CollUtil.isEmpty(holidaySettingIds)) {
return ListUtil.empty();
}
return holidayBalanceSettingMapper.selectList(new LambdaQueryWrapper<HolidayBalanceSettingDO>()
.in(HolidayBalanceSettingDO::getHolidaySettingId, holidaySettingIds));
}
@Override
public List<HolidayBalanceSettingDO> list(LambdaQueryWrapper<HolidayBalanceSettingDO> lambdaQueryWrapper) {
return holidayBalanceSettingMapper.selectList(lambdaQueryWrapper);
}
@Override
public void batchUpdate(List<HolidayBalanceSettingDO> editList) {
holidayBalanceSettingMapper.updateBatch(editList);
}
@Override
public List<HolidayBalanceSettingDO> getByIds(List<Long> holidayBalanceSettingIds) {
return holidayBalanceSettingMapper.selectBatchIds(holidayBalanceSettingIds);
}
}

View File

@ -1,13 +1,15 @@
package cn.iocoder.yudao.module.system.service.holiday.holidaysetting;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingEditVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingRespVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaybalancesetting.HolidayBalanceSettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting.HolidaySettingDO;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
/**
* 假期设置 Service 接口
@ -70,11 +72,27 @@ public interface HolidaySettingService {
*/
HolidaySettingRespVO getHolidaySettingRespVO(Long id);
LocalDateTime calculateNextReleaseDate(LocalDateTime now, HolidayBalanceSettingDO holidayBalanceSetting);
/**
* 编辑检测
* 获取所有假期设置
*
* @param createReqVO
* @return
*/
HolidaySettingEditVO editDetection(HolidaySettingSaveReqVO createReqVO);
List<HolidaySettingDO> getAll();
/**
* 获取所有假期设置
*
* @param userId
* @return
*/
List<HolidaySettingRespVO> getAllHolidaySetting(Long userId);
/**
* 根据ids获取
*
* @return
*/
List<HolidaySettingDO> listByIds(List<Long> holidaySettingIds);
}

View File

@ -1,25 +1,28 @@
package cn.iocoder.yudao.module.system.service.holiday.holidaysetting;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.holiday.holidaybalancesetting.vo.HolidayBalanceSettingRespVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingEditVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingRespVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.HolidaySettingSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.dto.RecalculateAssignedDTO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.*;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysettingrange.vo.HolidaySettingRangeRespVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysettingrange.vo.HolidaySettingRangeSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayworkingage.vo.HolidayWorkingAgeRespVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayworkingage.vo.HolidayWorkingAgeSaveReqVO;
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.holidaysettingrange.HolidaySettingRangeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuser.HolidayUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayworkingage.HolidayWorkingAgeDO;
import cn.iocoder.yudao.module.system.dal.mysql.holiday.holidaybalancesetting.HolidayBalanceSettingMapper;
import cn.iocoder.yudao.module.system.dal.mysql.holiday.holidaysetting.HolidaySettingMapper;
import cn.iocoder.yudao.module.system.dal.mysql.holiday.holidaysettingrange.HolidaySettingRangeMapper;
import cn.iocoder.yudao.module.system.dal.mysql.holiday.holidayuser.HolidayUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.holiday.holidayworkingage.HolidayWorkingAgeMapper;
import cn.iocoder.yudao.module.system.service.holiday.holidaybalancesetting.HolidayBalanceSettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysettingrange.HolidaySettingRangeService;
@ -27,13 +30,16 @@ import cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord.HolidayU
import cn.iocoder.yudao.module.system.service.holiday.holidayworkingage.HolidayWorkingAgeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.time.LocalDateTime;
import java.time.Month;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@ -43,6 +49,7 @@ import java.util.stream.Collectors;
*/
@Service
@Validated
@Slf4j
public class HolidaySettingServiceImpl implements HolidaySettingService {
@Resource
@ -61,6 +68,8 @@ public class HolidaySettingServiceImpl implements HolidaySettingService {
private HolidayWorkingAgeService holidayWorkingAgeService;
@Resource
private HolidayUserRecordService holidayUserRecordService;
@Resource
private HolidayUserMapper holidayUserMapper;
@Override
public Long createHolidaySetting(HolidaySettingSaveReqVO createReqVO) {
@ -86,7 +95,10 @@ public class HolidaySettingServiceImpl implements HolidaySettingService {
@Override
public HolidaySettingDO getHolidaySetting(Long id) {
return holidaySettingMapper.selectById(id);
HolidaySettingDO holidaySettingDO = holidaySettingMapper.selectById(id);
HolidayBalanceSettingDO holidayBalanceSettingDO = holidayBalanceSettingService.selectBySettingId(id);
holidaySettingDO.setHolidayBalanceSettingDO(holidayBalanceSettingDO);
return holidaySettingDO;
}
@Override
@ -98,12 +110,30 @@ public class HolidaySettingServiceImpl implements HolidaySettingService {
@Override
@Transactional(rollbackFor = Exception.class)
public Long createOrEdit(HolidaySettingSaveReqVO createReqVO) {
//假期设置
HolidaySettingDO holidaySetting = BeanUtils.toBean(createReqVO, HolidaySettingDO.class);
if (holidaySetting.getId() == null) {
this.batchSave(holidaySetting, createReqVO);
} else {
this.batchEdit(holidaySetting, createReqVO);
//假期余额设置
HolidayBalanceSettingDO holidayBalanceSetting = createReqVO.getHolidayBalanceSettingSaveReqVO() == null ? new HolidayBalanceSettingDO().init(holidaySetting.getId())
: BeanUtils.toBean(createReqVO.getHolidayBalanceSettingSaveReqVO().setHolidaySettingId(holidaySetting.getId()), HolidayBalanceSettingDO.class);
//假期额度工龄配置
List<HolidayWorkingAgeDO> holidayWorkingAges = new ArrayList<>();
if (createReqVO.getHolidayBalanceSettingSaveReqVO() != null &&
CollectionUtil.isNotEmpty(createReqVO.getHolidayBalanceSettingSaveReqVO().getHolidayWorkingAgeSaveReqVOS())) {
holidayWorkingAges = BeanUtils.toBean(createReqVO.getHolidayBalanceSettingSaveReqVO().getHolidayWorkingAgeSaveReqVOS(), HolidayWorkingAgeDO.class);
}
//假期规则人员范围
List<HolidaySettingRangeDO> holidaySettingRanges = new ArrayList<>();
if (CollectionUtil.isNotEmpty(createReqVO.getHolidaySettingRangeSaveReqVOS())) {
List<HolidaySettingRangeSaveReqVO> holidaySettingRangeSaveReqVOS = createReqVO.getHolidaySettingRangeSaveReqVOS();
holidaySettingRanges = BeanUtils.toBean(holidaySettingRangeSaveReqVOS, HolidaySettingRangeDO.class);
}
if (holidaySetting.getId() == null) {
this.batchSave(holidaySetting, holidayBalanceSetting, holidaySettingRanges, holidayWorkingAges);
return holidaySetting.getId();
}
this.batchEdit(holidaySetting, holidayBalanceSetting, holidaySettingRanges, holidayWorkingAges);
return holidaySetting.getId();
}
@ -125,140 +155,269 @@ public class HolidaySettingServiceImpl implements HolidaySettingService {
return respVO;
}
@Override
public HolidaySettingEditVO editDetection(HolidaySettingSaveReqVO createReqVO) {
// HolidaySettingEditVO holidaySettingEditVO = new HolidaySettingEditVO();
// // -- 编辑人员范围 - 被剔除范围的人员清空该请假类型
// // -- 编辑发放方式 - 员工历史余额将被清空 按新的方式重现发放余额
// // -- 编辑发放日期 - 假期余额重新计算
// Long holidaySettingId = createReqVO.getId();
// if (holidaySettingId == null) {
// return holidaySettingEditVO;
// }
// HolidaySettingDO holidaySettingDO = holidaySettingMapper.selectById(holidaySettingId);
// HolidayBalanceSettingDO holidayBalanceSettingDO = holidayBalanceSettingService.selectBySettingId(holidaySettingId);
// // -- 不是全公司 - 并且有假期余额可选
// if (holidaySettingDO.getApplicationScope() != 0 && holidayBalanceSettingDO.getStatus() != null && holidayBalanceSettingDO.getStatus() == 1) {
// // -- 查询原来的人员范围
// List<HolidaySettingRangeDO> oldHolidaySettingRanges = holidaySettingRangeMapper.selectList(new LambdaQueryWrapper<HolidaySettingRangeDO>()
// .eq(HolidaySettingRangeDO::getHolidaySettingId, holidaySettingId));
// // -- 过滤出所有需要删除的
// List<Long> ids = oldHolidaySettingRanges.stream().map(HolidaySettingRangeDO::getId).collect(Collectors.toList());
// List<Long> oldIds = oldHolidaySettingRanges.stream().map(HolidaySettingRangeDO::getId).collect(Collectors.toList());
// List<Long> delIds = new ArrayList<>(CollectionUtil.subtract(oldIds, ids));
// if (CollectionUtil.isNotEmpty(delIds)) {
// return holidaySettingEditVO.setPassFlag(0).setMsg("不在范围内的员工将无法请" + createReqVO.getName() + ",确认保存修改吗?");
// }
// }
return null;
}
private void batchSave(HolidaySettingDO holidaySetting, HolidaySettingSaveReqVO createReqVO) {
private void batchSave(HolidaySettingDO holidaySetting, HolidayBalanceSettingDO holidayBalanceSetting, List<HolidaySettingRangeDO> holidaySettingRanges, List<HolidayWorkingAgeDO> holidayWorkingAges) {
// ------- 插入假期设置
holidaySettingMapper.insert(holidaySetting);
// -- 如果人员范围不为空的话
List<HolidaySettingRangeDO> holidaySettingRangeDOS = new ArrayList<>();
if (CollectionUtil.isNotEmpty(createReqVO.getHolidaySettingRangeSaveReqVOS())) {
List<HolidaySettingRangeSaveReqVO> holidaySettingRangeSaveReqVOS = createReqVO.getHolidaySettingRangeSaveReqVOS();
holidaySettingRangeDOS = BeanUtils.toBean(holidaySettingRangeSaveReqVOS, HolidaySettingRangeDO.class);
holidaySettingRangeDOS.forEach(holidaySettingRangeDO -> holidaySettingRangeDO.setHolidaySettingId(holidaySetting.getId()));
if (CollectionUtil.isNotEmpty(holidaySettingRanges)) {
holidaySettingRanges.forEach(holidaySettingRangeDO -> holidaySettingRangeDO.setHolidaySettingId(holidaySetting.getId()));
// ---------- 插入假期规则人员范围
holidaySettingRangeMapper.insertBatch(holidaySettingRangeDOS);
holidaySettingRangeMapper.insertBatch(holidaySettingRanges);
}
//本次发放时间 要不要加上- 不然的话我都不知道什么时候发放下一次怎么办呢
// ---------- 插入假期余额设置 如果没有的话初始化一个关闭的对象
HolidayBalanceSettingDO holidayBalanceSettingDO = createReqVO.getHolidayBalanceSettingSaveReqVO() == null ? new HolidayBalanceSettingDO().init(holidaySetting.getId())
: BeanUtils.toBean(createReqVO.getHolidayBalanceSettingSaveReqVO().setHolidaySettingId(holidaySetting.getId()), HolidayBalanceSettingDO.class);
holidayBalanceSettingMapper.insert(holidayBalanceSettingDO);
LocalDateTime issueTime = this.calculateNextReleaseDate(LocalDateTime.now(), holidayBalanceSetting);
holidayBalanceSetting.setHolidaySettingId(holidaySetting.getId());
holidayBalanceSetting.setIssueTime(issueTime);
holidayBalanceSettingMapper.insert(holidayBalanceSetting);
// --------------- 插入 假期额度工龄配置
List<HolidayWorkingAgeDO> holidayWorkingAgeDOS = new ArrayList<>();
if (createReqVO.getHolidayBalanceSettingSaveReqVO() != null &&
CollectionUtil.isNotEmpty(createReqVO.getHolidayBalanceSettingSaveReqVO().getHolidayWorkingAgeSaveReqVOS())) {
List<HolidayWorkingAgeSaveReqVO> holidayWorkingAgeSaveReqVOS = createReqVO.getHolidayBalanceSettingSaveReqVO().getHolidayWorkingAgeSaveReqVOS();
holidayWorkingAgeSaveReqVOS.forEach(holidayWorkingAgeSaveReqVO -> {
holidayWorkingAgeSaveReqVO.setHolidaySettingId(holidaySetting.getId());
holidayWorkingAgeSaveReqVO.setHolidayBalanceSettingId(holidayBalanceSettingDO.getId());
if (CollectionUtil.isNotEmpty(holidayWorkingAges)) {
holidayWorkingAges.forEach(vo -> {
vo.setHolidaySettingId(holidaySetting.getId());
vo.setHolidayBalanceSettingId(holidayBalanceSetting.getId());
});
holidayWorkingAgeDOS = BeanUtils.toBean(holidayWorkingAgeSaveReqVOS, HolidayWorkingAgeDO.class);
holidayWorkingAgeMapper.insertBatch(holidayWorkingAgeDOS);
holidayWorkingAgeMapper.insertBatch(holidayWorkingAges);
}
// -- 计算假期
if (holidayBalanceSettingDO.getStatus() == 1) {
holidayUserRecordService.init(holidaySetting, holidaySettingRangeDOS, holidayBalanceSettingDO, holidayWorkingAgeDOS);
if (holidayBalanceSetting.getStatus() == 1) {
holidayUserRecordService.grant(holidaySetting, holidaySettingRanges, holidayBalanceSetting, holidayWorkingAges);
}
}
private void batchEdit(HolidaySettingDO holidaySetting, HolidaySettingSaveReqVO createReqVO) {
// -- 更新假期设置
holidaySettingMapper.updateById(holidaySetting);
// -- 查询人员范围列表 判断是否需要更新删除
LambdaQueryWrapper<HolidaySettingRangeDO> lambdaQueryWrapper = new LambdaQueryWrapper<HolidaySettingRangeDO>()
.eq(HolidaySettingRangeDO::getHolidaySettingId, holidaySetting.getId());
List<HolidaySettingRangeDO> oldHolidaySettingRanges = holidaySettingRangeMapper.selectList(lambdaQueryWrapper);
if (CollectionUtil.isEmpty(createReqVO.getHolidaySettingRangeSaveReqVOS())) {
holidaySettingRangeMapper.delete(lambdaQueryWrapper);
// // 清空余额
// holidayUserRecordService.clear(holidaySetting.getId(), null);
} else {
List<HolidaySettingRangeDO> holidaySettingRangeDOS = BeanUtils.toBean(createReqVO.getHolidaySettingRangeSaveReqVOS(), HolidaySettingRangeDO.class);
holidaySettingRangeDOS.forEach(holidaySettingRangeDO -> holidaySettingRangeDO.setHolidaySettingId(holidaySetting.getId()));
// -- 过滤出所有需要添加的
List<HolidaySettingRangeDO> saveList = holidaySettingRangeDOS.stream().filter(a -> a.getId() == null).collect(Collectors.toList());
if (!CollectionUtil.isEmpty(saveList)) {
holidaySettingRangeMapper.insertBatch(saveList);
}
// -- 过滤出所有需要删除的
List<Long> ids = holidaySettingRangeDOS.stream().map(HolidaySettingRangeDO::getId).collect(Collectors.toList());
List<Long> oldIds = oldHolidaySettingRanges.stream().map(HolidaySettingRangeDO::getId).collect(Collectors.toList());
List<Long> delIds = new ArrayList<>(CollectionUtil.subtract(oldIds, ids));
if (CollectionUtil.isNotEmpty(delIds)) {
List<HolidaySettingRangeDO> delList = oldHolidaySettingRanges.stream().filter(a -> delIds.contains(a.getId())).collect(Collectors.toList());
holidaySettingRangeMapper.deleteBatchIds(delIds);
// // 清空余额
// holidayUserRecordService.clear(holidaySetting.getId(), delList);
/**
* 计算下一次发放日期
*
* @param now
* @param holidayBalanceSetting
* @return
*/
@Override
public LocalDateTime calculateNextReleaseDate(LocalDateTime now, HolidayBalanceSettingDO holidayBalanceSetting) {
LocalDateTime issueTime = null;
if (holidayBalanceSetting.getType() == 1) {
//获取下个月几号
issueTime = now.withDayOfMonth(holidayBalanceSetting.getIssueTimeType()).plusMonths(1);
} else if (holidayBalanceSetting.getType() == 2) {
if (holidayBalanceSetting.getIssueTimeType() == 2) {
//获取明年1月1号
issueTime = now.plusYears(1).withMonth(Month.JANUARY.getValue()).withDayOfMonth(1);
}
}
// -- 取一天的开始时间
if (issueTime != null) {
issueTime = LocalDateTimeUtil.beginOfDay(issueTime);
}
return issueTime;
}
// -- 更新假期余额设置
HolidayBalanceSettingDO holidayBalanceSettingDO = holidayBalanceSettingService.selectBySettingId(holidaySetting.getId());
holidayBalanceSettingDO = createReqVO.getHolidayBalanceSettingSaveReqVO() == null ? holidayBalanceSettingDO.setStatus(0)
: BeanUtils.toBean(createReqVO.getHolidayBalanceSettingSaveReqVO().setHolidaySettingId(holidaySetting.getId()), HolidayBalanceSettingDO.class);
holidayBalanceSettingMapper.updateById(holidayBalanceSettingDO);
@Override
public List<HolidaySettingDO> getAll() {
return holidaySettingMapper.selectList();
}
// --------------- 更新 假期额度工龄配置
List<HolidayWorkingAgeDO> oldHolidayWorkingAgeDOS = holidayWorkingAgeService.selectBySettingId(holidaySetting.getId());
if (createReqVO.getHolidayBalanceSettingSaveReqVO() != null &&
CollectionUtil.isNotEmpty(createReqVO.getHolidayBalanceSettingSaveReqVO().getHolidayWorkingAgeSaveReqVOS())) {
List<HolidayWorkingAgeSaveReqVO> holidayWorkingAgeSaveReqVOS = createReqVO.getHolidayBalanceSettingSaveReqVO().getHolidayWorkingAgeSaveReqVOS();
List<HolidayWorkingAgeDO> holidayWorkingAgeDOS = BeanUtils.toBean(holidayWorkingAgeSaveReqVOS, HolidayWorkingAgeDO.class);
for (HolidayWorkingAgeSaveReqVO holidayWorkingAgeSaveReqVO : holidayWorkingAgeSaveReqVOS) {
holidayWorkingAgeSaveReqVO.setHolidaySettingId(holidaySetting.getId());
holidayWorkingAgeSaveReqVO.setHolidayBalanceSettingId(holidayBalanceSettingDO.getId());
@Override
public List<HolidaySettingRespVO> getAllHolidaySetting(Long userId) {
List<HolidaySettingDO> allList = this.getAll();
List<HolidayUserDO> items = holidayUserMapper.selectList(new LambdaQueryWrapper<HolidayUserDO>().eq(HolidayUserDO::getUserId, userId));
Map<Long, HolidayUserDO> HolidayUserMap = MapUtil.empty();
if (CollUtil.isNotEmpty(items)) {
HolidayUserMap = items.stream().collect(Collectors.toMap(HolidayUserDO::getHolidayBalanceSettingId, holidayUserDO -> holidayUserDO));
}
List<HolidaySettingRespVO> list = new ArrayList<>();
List<HolidaySettingRespVO> vos = BeanUtils.toBean(allList, HolidaySettingRespVO.class);
List<HolidayBalanceSettingDO> holidayBalanceSettingDOS = holidayBalanceSettingService.getHolidayBalanceSettingByHolidaySettingIds(allList.stream().map(HolidaySettingDO::getId).collect(Collectors.toList()));
List<HolidayBalanceSettingRespVO> holidayBalanceSettingRespVOS = BeanUtils.toBean(holidayBalanceSettingDOS, HolidayBalanceSettingRespVO.class);
Map<Long, HolidayBalanceSettingRespVO> holidayBalanceSettingRespVOMap = holidayBalanceSettingRespVOS.stream().collect(Collectors.toMap(HolidayBalanceSettingRespVO::getHolidaySettingId, Function.identity()));
for (HolidaySettingRespVO vo : vos) {
HolidayBalanceSettingRespVO holidayBalanceSettingRespVO = holidayBalanceSettingRespVOMap.get(vo.getId());
HolidayUserDO holidayUserDO = HolidayUserMap.get(vo.getId());
// -- 过滤掉不适用的
if ((holidayBalanceSettingRespVO != null && holidayBalanceSettingRespVO.getStatus() == 1) && holidayUserDO == null) {
continue;
} else {
vo.setHolidayBalance(holidayUserDO == null ? null : holidayUserDO.getHolidayBalance());
}
List<HolidayWorkingAgeDO> saveList = holidayWorkingAgeDOS.stream().filter(a -> a.getId() == null).collect(Collectors.toList());
List<HolidayWorkingAgeDO> editList = holidayWorkingAgeDOS.stream().filter(a -> a.getId() != null).collect(Collectors.toList());
vo.setHolidayBalanceSettingRespVO(holidayBalanceSettingRespVOMap.get(vo.getId()));
list.add(vo);
}
return list;
}
@Override
public List<HolidaySettingDO> listByIds(List<Long> holidaySettingIds) {
if (CollectionUtil.isEmpty(holidaySettingIds)){
return Collections.emptyList();
}
return holidaySettingMapper.selectBatchIds(holidaySettingIds);
}
/**
* 编辑假期设置
* 让我们来捋一下逻辑 - 这里有下面4个情况要处理
* 1.假期余额设置 开关 需要清空所有相关人员的假期余额
* 2.人员变动 需要清空多余人员的请假额度
* 3.假期发放方式调整 历史余额将会被清空 按新的方式重新发送
* 4.发放日期调整 修改发放日期后假期余额将按新规则重新计算 - 计算规则历史请假记录扣减当前年度余额例如把发放日期从2019年1月1日1改到2019年6月1日之前在1月1日和6月1日之间的请假记录也算在2019年的请假额度里
* 5.更改额度配置规则 修改余额发放方式后假期余额将按新规则重新发放
*/
private void batchEdit(HolidaySettingDO holidaySetting, HolidayBalanceSettingDO holidayBalanceSetting, List<HolidaySettingRangeDO> holidaySettingRanges, List<HolidayWorkingAgeDO> holidayWorkingAges) {
// -- 更新假期设置
holidaySettingMapper.updateById(holidaySetting);
// -- 更新假期余额设置
HolidayBalanceSettingDO oldHolidayBalanceSettingDO = holidayBalanceSettingService.selectBySettingId(holidaySetting.getId());
// -- 更新假期额度工龄配置
boolean changeFlag = this.updateHolidayQuotaAndSeniorityConfiguration(holidaySetting.getId(), oldHolidayBalanceSettingDO.getId(), holidayWorkingAges);
// -- 1.人员变动 需要清空多余人员/或者增加新的人员 - 里面已做清空人员处理 - 还没有做清空人员假期余额 在后面的发放中处理
PersonnelChangesVO personnelChangesVO = this.personnelChanges(holidaySetting.getId(), holidaySettingRanges);
// -- 2.判断假期余额设置 开关
// -- 3.假期发放方式调整 历史余额将会被清空 按新的方式重新发送
// -- 4.发放日期调整 修改发放日期后假期余额将按新规则重新计算
// -- 5.更改额度配置规则 修改余额发放方式后假期余额将按新规则重新发放
DetermineHolidayBalanceSettingSwitchVO settingSwitch = this.determineHolidayBalanceSettingSwitch(holidayBalanceSetting, oldHolidayBalanceSettingDO, changeFlag);
LocalDateTime now = LocalDateTime.now();
// -- 如果我什么都没改 - 岂不是也会更新 那么这个月的不久发放不了了么对吧 我什么都没改的话是不会进行发放的 - 所以这里需要判断他有没有改动什么导致他发放假期 从而更新时间
if (holidayBalanceSetting.getIssueTime() != null || (settingSwitch.isChangeFlag() && settingSwitch.isSwitchFlag()) ||
settingSwitch.isAdjustTypeFlag() || settingSwitch.isDateAdjustFlag() || settingSwitch.isQuotaRuleFlag()) {
LocalDateTime issueTime = this.calculateNextReleaseDate(now, holidayBalanceSetting);
holidayBalanceSetting.setIssueTime(issueTime);
}
holidayBalanceSettingMapper.updateById(holidayBalanceSetting);
holidayUserRecordService.recalculateAssigned(RecalculateAssignedDTO.builder()
.holidaySetting(holidaySetting)
.holidayBalanceSetting(holidayBalanceSetting)
.holidayWorkingAges(holidayWorkingAges)
.personnelChangesVO(personnelChangesVO)
.determineHolidayBalanceSettingSwitchVO(settingSwitch).build());
}
/**
* 更新假期额度工龄配置
*
* @param holidaySettingId
* @param holidayBalanceSettingId
* @param holidayWorkingAges
*/
private boolean updateHolidayQuotaAndSeniorityConfiguration(Long holidaySettingId, Long holidayBalanceSettingId, List<HolidayWorkingAgeDO> holidayWorkingAges) {
List<HolidayWorkingAgeDO> oldHolidayWorkingAgeDOS = holidayWorkingAgeService.selectBySettingId(holidaySettingId);
boolean flag = false;
if (CollectionUtil.isNotEmpty(holidayWorkingAges)) {
for (HolidayWorkingAgeDO workingAgeDO : holidayWorkingAges) {
workingAgeDO.setHolidaySettingId(holidaySettingId);
workingAgeDO.setHolidayBalanceSettingId(holidayBalanceSettingId);
}
List<HolidayWorkingAgeDO> saveList = holidayWorkingAges.stream().filter(a -> a.getId() == null).collect(Collectors.toList());
List<HolidayWorkingAgeDO> editList = holidayWorkingAges.stream().filter(a -> a.getId() != null).collect(Collectors.toList());
if (!saveList.isEmpty()) {
holidayWorkingAgeMapper.insertBatch(saveList);
flag = true;
}
if (!editList.isEmpty()) {
// - 修改的列表不是 老的子集
if (!editList.isEmpty() && !CollectionUtil.containsAll(oldHolidayWorkingAgeDOS, editList)) {
holidayWorkingAgeMapper.updateBatch(editList);
flag = true;
}
List<Long> oldIds = oldHolidayWorkingAgeDOS.stream().map(HolidayWorkingAgeDO::getId).collect(Collectors.toList());
List<Long> newIds = editList.stream().map(HolidayWorkingAgeDO::getId).collect(Collectors.toList());
List<Long> delIds = new ArrayList<>(CollectionUtil.subtract(oldIds, newIds));
if (!delIds.isEmpty()) {
holidayWorkingAgeMapper.deleteBatchIds(delIds);
flag = true;
}
}
return flag;
}
public static void main(String[] args) {
List<HolidayWorkingAgeDO> oldList = new ArrayList<>();
oldList.add(new HolidayWorkingAgeDO().setId(1L).setHolidaySettingId(1L).setNum(1));
oldList.add(new HolidayWorkingAgeDO().setId(2L).setHolidaySettingId(1L).setNum(1));
oldList.add(new HolidayWorkingAgeDO().setId(3L).setHolidaySettingId(1L).setNum(1));
oldList.add(new HolidayWorkingAgeDO().setId(4L).setHolidaySettingId(1L).setNum(1));
List<HolidayWorkingAgeDO> editList = new ArrayList<>();
editList.add(new HolidayWorkingAgeDO().setId(1L).setHolidaySettingId(1L).setNum(2));
editList.add(new HolidayWorkingAgeDO().setId(3L).setHolidaySettingId(1L).setNum(1));
editList.add(new HolidayWorkingAgeDO().setId(4L).setHolidaySettingId(1L).setNum(1));
System.out.println();
}
/**
* 人员范围计算 (获取到需要删除or新增的人员范围列表)
*
* @param holidaySettingId
* @param holidaySettingRanges
* @return
*/
private PersonnelChangesVO personnelChanges(Long holidaySettingId, List<HolidaySettingRangeDO> holidaySettingRanges) {
PersonnelChangesVO vo = new PersonnelChangesVO();
List<HolidaySettingRangeDO> oldAllList;
List<HolidaySettingRangeDO> newAllList;
List<HolidaySettingRangeDO> delRangeList = new ArrayList<>();
List<HolidaySettingRangeDO> saveRangeList = new ArrayList<>();
// -- 查询人员范围列表 判断是否需要更新删除
LambdaQueryWrapper<HolidaySettingRangeDO> lambdaQueryWrapper = new LambdaQueryWrapper<HolidaySettingRangeDO>()
.eq(HolidaySettingRangeDO::getHolidaySettingId, holidaySettingId);
List<HolidaySettingRangeDO> oldHolidaySettingRanges = holidaySettingRangeMapper.selectList(lambdaQueryWrapper);
newAllList = oldHolidaySettingRanges;
oldAllList = oldHolidaySettingRanges;
if (CollectionUtil.isEmpty(holidaySettingRanges)) {
delRangeList.addAll(oldHolidaySettingRanges);
} else {
holidaySettingRanges.forEach(holidaySettingRangeDO -> holidaySettingRangeDO.setHolidaySettingId(holidaySettingId));
// -- 过滤出所有需要添加的
List<HolidaySettingRangeDO> saveList = holidaySettingRanges.stream().filter(a -> a.getId() == null).collect(Collectors.toList());
if (!CollectionUtil.isEmpty(saveList)) {
saveRangeList.addAll(saveList);
}
// -- 过滤出所有需要删除的
List<Long> ids = holidaySettingRanges.stream().map(HolidaySettingRangeDO::getId).filter(Objects::nonNull).collect(Collectors.toList());
List<Long> oldIds = oldHolidaySettingRanges.stream().map(HolidaySettingRangeDO::getId).collect(Collectors.toList());
List<Long> delIds = new ArrayList<>(CollectionUtil.subtract(oldIds, ids));
if (CollectionUtil.isNotEmpty(delIds)) {
List<HolidaySettingRangeDO> delList = oldHolidaySettingRanges.stream().filter(a -> delIds.contains(a.getId())).collect(Collectors.toList());
delRangeList.addAll(delList);
}
}
if (CollectionUtil.isNotEmpty(delRangeList)) {
newAllList.removeAll(delRangeList);
holidaySettingRangeMapper.deleteBatchIds(delRangeList);
}
if (CollectionUtil.isNotEmpty(saveRangeList)) {
newAllList.addAll(saveRangeList);
holidaySettingRangeMapper.insertBatch(saveRangeList);
}
return vo.setOldAllList(oldAllList).setSaveList(saveRangeList).setDelList(delRangeList).setNewAllList(newAllList);
}
/**
* 判断假期余额设置
*
* @param holidayBalanceSetting 新的假期余额设置
* @param oldHolidayBalanceSettingDO 老的假期余额设置
* @param changeFlag
*/
private DetermineHolidayBalanceSettingSwitchVO determineHolidayBalanceSettingSwitch(HolidayBalanceSettingDO holidayBalanceSetting, HolidayBalanceSettingDO oldHolidayBalanceSettingDO, boolean changeFlag) {
boolean quotaRuleFlag = !holidayBalanceSetting.getQuotaRule().equals(oldHolidayBalanceSettingDO.getQuotaRule());
// - 如果两个额度相等并且是固定额度 并且两个值不想等 || 或者阶梯有更改
boolean quotaFlag = oldHolidayBalanceSettingDO.getQuotaRule() == 1 ? !holidayBalanceSetting.getQuota().equals(oldHolidayBalanceSettingDO.getQuota()) : changeFlag;
return DetermineHolidayBalanceSettingSwitchVO.builder()
.changeFlag(!Objects.equals(holidayBalanceSetting.getStatus(), oldHolidayBalanceSettingDO.getStatus()))
.switchFlag(Constants.TRUE.equals(holidayBalanceSetting.getStatus()))
.adjustTypeFlag(!holidayBalanceSetting.getType().equals(oldHolidayBalanceSettingDO.getType()))
.dateAdjustFlag(!holidayBalanceSetting.getIssueTimeType().equals(oldHolidayBalanceSettingDO.getIssueTimeType()))
.quotaRuleFlag(quotaRuleFlag)
.quotaFlag(quotaRuleFlag || quotaFlag)
.build();
}
}

View File

@ -69,4 +69,19 @@ public interface HolidaySettingRangeService {
* @return
*/
List<AdminUserDO> getUsersByRange(List<HolidaySettingRangeDO> holidaySettingRangeDOS);
/**
* 根据假期设置id获取列表
*
* @return
*/
List<HolidaySettingRangeDO> getListByHolidaySettingId(Long holidaySettingId);
/**
* 根据假期设置ids获取列表
*
* @param holidaySettingIds
* @return
*/
List<HolidaySettingRangeDO> getListByHolidaySettingIds(List<Long> holidaySettingIds);
}

View File

@ -87,10 +87,25 @@ public class HolidaySettingRangeServiceImpl implements HolidaySettingRangeServic
if (CollUtil.isNotEmpty(deptIds)) {
list.addAll(adminUserService.getAllList(new UserDTO().setDeptIds(deptIds)));
}
if (CollUtil.isNotEmpty(groupIds)) {
if (CollUtil.isNotEmpty(userIds)) {
list.addAll(adminUserService.getAllList(new UserDTO().setUserIds(userIds)));
}
return list.stream().distinct().collect(Collectors.toList());
}
@Override
public List<HolidaySettingRangeDO> getListByHolidaySettingId(Long holidaySettingId) {
return holidaySettingRangeMapper.selectList(new LambdaQueryWrapper<HolidaySettingRangeDO>()
.eq(HolidaySettingRangeDO::getHolidaySettingId, holidaySettingId));
}
@Override
public List<HolidaySettingRangeDO> getListByHolidaySettingIds(List<Long> holidaySettingIds) {
if (CollUtil.isEmpty(holidaySettingIds)){
return Collections.emptyList();
}
return holidaySettingRangeMapper.selectList(new LambdaQueryWrapper<HolidaySettingRangeDO>()
.in(HolidaySettingRangeDO::getHolidaySettingId, holidaySettingIds));
}
}

View File

@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.system.service.holiday.holidayuser;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuser.HolidayUserDO;
import javax.validation.Valid;
@ -52,4 +54,9 @@ public interface HolidayUserService {
*/
PageResult<HolidayUserDO> getHolidayUserPage(HolidayUserPageReqVO pageReqVO);
/**
* 获得员工假期动态列表
* @return
*/
HolidayUserVO getHolidayUserDynamic(UserPageReqVO userPageReqVO);
}

View File

@ -1,15 +1,31 @@
package cn.iocoder.yudao.module.system.service.holiday.holidayuser;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.HolidayUserSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuser.vo.*;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO;
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.holidayuser.HolidayUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.holiday.holidayuser.HolidayUserMapper;
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.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 员工假期 Service 实现类
@ -22,6 +38,15 @@ public class HolidayUserServiceImpl implements HolidayUserService {
@Resource
private HolidayUserMapper holidayUserMapper;
@Resource
@Lazy
private HolidaySettingService holidaySettingService;
@Resource
@Lazy
private HolidayBalanceSettingService holidayBalanceSettingService;
@Resource
@Lazy
private AdminUserService adminUserService;
@Override
public Long createHolidayUser(HolidayUserSaveReqVO createReqVO) {
@ -54,4 +79,69 @@ public class HolidayUserServiceImpl implements HolidayUserService {
public PageResult<HolidayUserDO> getHolidayUserPage(HolidayUserPageReqVO pageReqVO) {
return holidayUserMapper.selectPage(pageReqVO);
}
@Override
public HolidayUserVO getHolidayUserDynamic(UserPageReqVO userPageReqVO) {
HolidayUserVO holidayUser = new HolidayUserVO();
//获取用户列表 -
Map<Integer, String> headers = new HashMap<>();
headers.put(1, "姓名");
headers.put(2, "部门");
headers.put(3, "入职时间");
// -- 查询假期的类型
List<HolidaySettingDO> holidaySettings = holidaySettingService.getAll();
// 根据假期设置获取到假期余额设置
Map<Long, HolidayBalanceSettingDO> holidayBalanceSettingMap = holidayBalanceSettingService.selectBySettingIds(holidaySettings.stream().map(HolidaySettingDO::getId).collect(Collectors.toList()));
int index = 4;
for (HolidaySettingDO holidaySetting : holidaySettings) {
headers.put(index, holidaySetting.getName());
index++;
}
holidayUser.setHeaders(headers);
// -- 获取用户列表
PageResult<AdminUserDO> pageResult = adminUserService.getUserBringDeptPage(userPageReqVO);
List<HolidayUserValuePageVO> list = new ArrayList<>();
// -- 获取这些用户所有的假期余额
List<Long> userIds = pageResult.getList().stream().map(AdminUserDO::getId).collect(Collectors.toList());
if (CollUtil.isNotEmpty(userIds)) {
List<HolidayUserDO> holidayUserDOS = holidayUserMapper.selectList(new LambdaQueryWrapper<HolidayUserDO>().in(HolidayUserDO::getUserId, userIds));
Map<Long, List<HolidayUserDO>> holidayUserMaps = holidayUserDOS.stream().collect(Collectors.groupingBy(HolidayUserDO::getUserId));
for (AdminUserDO adminUserDO : pageResult.getList()) {
HolidayUserValuePageVO holidayUserValuePageVO = new HolidayUserValuePageVO();
holidayUserValuePageVO.setUserId(adminUserDO.getId());
holidayUserValuePageVO.getListOfHolidayTypes().put(1, new HolidayUserMapVO().setValue(adminUserDO.getNickname()));
holidayUserValuePageVO.getListOfHolidayTypes().put(2, new HolidayUserMapVO().setValue(adminUserDO.getDeptName()));
holidayUserValuePageVO.getListOfHolidayTypes().put(3, new HolidayUserMapVO().setValue(adminUserDO.getEntryDate() == null ? "未设置" : adminUserDO.getEntryDate().format(Constants.REPO_DATE_FORMAT)));
List<HolidayUserDO> items = holidayUserMaps.get(adminUserDO.getId());
Map<Long, HolidayUserDO> HolidayUserMap = MapUtil.empty();
if (CollUtil.isNotEmpty(items)) {
HolidayUserMap = items.stream().collect(Collectors.toMap(HolidayUserDO::getHolidayBalanceSettingId, holidayUserDO -> holidayUserDO));
}
// ------- 还有每个用户的假期余额
index = 4;
for (HolidaySettingDO holidaySetting : holidaySettings) {
HolidayBalanceSettingDO holidayBalanceSettingDO = holidayBalanceSettingMap.get(holidaySetting.getId());
String value = "";
if (holidayBalanceSettingDO.getStatus() == 0) {
value = "不限制余额";
} else {
HolidayUserDO holidayUserDO = HolidayUserMap.get(holidaySetting.getId());
if (holidayUserDO == null) {
value = "不适用";
} else {
value = holidayUserDO.getHolidayBalance().toString();
}
}
holidayUserValuePageVO.getListOfHolidayTypes().put(index, new HolidayUserMapVO().setId(holidaySetting.getId()).setValue(value));
index++;
}
list.add(holidayUserValuePageVO);
}
}
// --
PageResult<HolidayUserValuePageVO> result = new PageResult<>(list, pageResult.getTotal());
holidayUser.setPage(result);
return holidayUser;
}
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.api.holiday.dto.CreateUserHolidayDTO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.dto.RecalculateAssignedDTO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecord.vo.HolidayUserRecordPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecord.vo.HolidayUserRecordSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaybalancesetting.HolidayBalanceSettingDO;
@ -8,9 +10,13 @@ import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting.Holi
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysettingrange.HolidaySettingRangeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayuserrecord.HolidayUserRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayworkingage.HolidayWorkingAgeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 员工假期记录 Service 接口
@ -20,34 +26,35 @@ import java.util.List;
public interface HolidayUserRecordService {
/**
* 创建员工假期记录
* 创建员工假期记录 用于管理员操作用户假期
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createHolidayUserRecord(@Valid HolidayUserRecordSaveReqVO createReqVO);
void createHolidayUserRecord(@Valid HolidayUserRecordSaveReqVO createReqVO);
/**
* 更新员工假期记录
* 创建用户请假(用于用户主动请假)
*
* @param updateReqVO 更新信息
* @param dto
*/
void updateHolidayUserRecord(@Valid HolidayUserRecordSaveReqVO updateReqVO);
void createUserHoliday(CreateUserHolidayDTO dto);
/**
* 删除员工假期记录
* 创建用户请假(用于用户主动请假)
*
* @param id 编号
* @param holidayUserRecords
*/
void deleteHolidayUserRecord(Long id);
void beOverdue(List<HolidayUserRecordDO> holidayUserRecords);
/**
* 获得员工假期记录
*
* @param id 编号
* @param userId 编号
* @param holidaySettingId
* @return 员工假期记录
*/
HolidayUserRecordDO getHolidayUserRecord(Long id);
List<HolidayUserRecordDO> getHolidayUserRecord(Long userId, Long holidaySettingId);
/**
* 获得员工假期记录分页
@ -58,15 +65,78 @@ public interface HolidayUserRecordService {
PageResult<HolidayUserRecordDO> getHolidayUserRecordPage(HolidayUserRecordPageReqVO pageReqVO);
/**
* 设置完假期后 - 初始化用户的假期
* 设置完假期后 - 初始化用户的假期 发放
*/
void init(HolidaySettingDO holidaySetting, List<HolidaySettingRangeDO> holidaySettingRangeDOS, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS);
/**
* 发放假期
*
* @param holidaySetting
* @param holidaySettingRangeDOS
* @param holidayBalanceSettingDO
* @param holidayWorkingAgeDOS
*/
void grant(HolidaySettingDO holidaySetting, List<HolidaySettingRangeDO> holidaySettingRangeDOS, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS);
/**
* 清空假期余额
*
* @param holidaySettingId
* @param holidaySettingRangeDOS 为null 的话则代表清空所有用户的
* @param holidaySettingRangeDOS 为null 的话则代表清空所有用户的
*/
void clear(Long holidaySettingId, List<HolidaySettingRangeDO> holidaySettingRangeDOS);
/**
* 重新计算分配假期
*
* @param dto
*/
void recalculateAssigned(RecalculateAssignedDTO dto);
/**
* 假期有效期计算
*
* @param now 当前时间
* @param usersIds 用户ids
* @param holidayBalanceSettingDO 假期设置
* @return
*/
Map<Long, LocalDateTime> validityPeriodCalculation(LocalDateTime now, List<Long> usersIds, HolidayBalanceSettingDO holidayBalanceSettingDO);
/**
* 假期有效期计算
*
* @param now 当前时间
* @param userId 用户id
* @param holidayBalanceSettingDO 假期设置
* @return
*/
Map<Long, LocalDateTime> validityPeriodCalculation(LocalDateTime now, Long userId, HolidayBalanceSettingDO holidayBalanceSettingDO);
Map<Long, BigDecimal> getQuotaMap(List<AdminUserDO> users, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS);
/**
* 获取过期的假期 还没有进行扣减的 剩余余额大于0的
*
* @param now
* @return
*/
List<HolidayUserRecordDO> getHolidayBeOverdue(LocalDateTime now);
/**
* 获取过期提醒列表
*
* @param now
* @return
*/
List<HolidayUserRecordDO> getHolidayRemind(LocalDateTime now);
/**
* 修改状态为已提醒
*
* @param list
*/
void editReminder(List<HolidayUserRecordDO> list);
}

View File

@ -1,8 +1,13 @@
package cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.system.api.holiday.dto.CreateUserHolidayDTO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.dto.RecalculateAssignedDTO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidaysetting.vo.DetermineHolidayBalanceSettingSwitchVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecord.vo.HolidayUserRecordPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayuserrecord.vo.HolidayUserRecordSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaybalancesetting.HolidayBalanceSettingDO;
@ -14,23 +19,33 @@ import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayworkingage.H
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.holiday.holidayuser.HolidayUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.holiday.holidayuserrecord.HolidayUserRecordMapper;
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.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.Period;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
/**
* 员工假期记录 Service 实现类
*
@ -38,6 +53,7 @@ import java.util.stream.Collectors;
*/
@Service
@Validated
@Slf4j
public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
@Resource
@ -49,71 +65,131 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
private AdminUserService adminUserService;
@Resource
private HolidaySettingRangeService holidaySettingRangeService;
@Resource
@Lazy
private HolidaySettingService holidaySettingService;
@Override
public Long createHolidayUserRecord(HolidayUserRecordSaveReqVO createReqVO) {
// 插入
HolidayUserRecordDO holidayUserRecord = BeanUtils.toBean(createReqVO, HolidayUserRecordDO.class);
holidayUserRecordMapper.insert(holidayUserRecord);
// 返回
return holidayUserRecord.getId();
}
@Override
public void updateHolidayUserRecord(HolidayUserRecordSaveReqVO updateReqVO) {
// 更新
HolidayUserRecordDO updateObj = BeanUtils.toBean(updateReqVO, HolidayUserRecordDO.class);
holidayUserRecordMapper.updateById(updateObj);
}
@Override
public void deleteHolidayUserRecord(Long id) {
// 删除
holidayUserRecordMapper.deleteById(id);
}
@Override
public HolidayUserRecordDO getHolidayUserRecord(Long id) {
return holidayUserRecordMapper.selectById(id);
}
@Override
public PageResult<HolidayUserRecordDO> getHolidayUserRecordPage(HolidayUserRecordPageReqVO pageReqVO) {
return holidayUserRecordMapper.selectPage(pageReqVO);
}
@Override
public void init(HolidaySettingDO holidaySetting, List<HolidaySettingRangeDO> holidaySettingRangeDOS, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS) {
// -- 先查询出收益用户
List<AdminUserDO> users;
if (holidaySetting.getApplicationScope() == 0) {
users = adminUserService.getAllList(0, 1, null);
} else {
users = holidaySettingRangeService.getUsersByRange(holidaySettingRangeDOS);
}
public void createHolidayUserRecord(HolidayUserRecordSaveReqVO createReqVO) {
// 获取当前登录用户信息
AdminUserDO myself = adminUserService.getUser(getLoginUserId());
// -- 计算获取每个人的假期额度
Map<Long, BigDecimal> userQuotaMap = this.getQuotaMap(users, holidayBalanceSettingDO, holidayWorkingAgeDOS);
Long userId = createReqVO.getUserId();
AdminUserDO targetUser = adminUserService.getUser(userId);
LocalDateTime now = LocalDateTime.now();
Map<Long, BigDecimal> userQuotaMap = new HashMap<>();
List<Long> userIds = Collections.singletonList(userId);
HolidaySettingDO holidaySetting = holidaySettingService.getHolidaySetting(createReqVO.getHolidaySettingId());
HolidayBalanceSettingDO holidayBalanceSettingDO = holidaySetting.getHolidayBalanceSettingDO();
userQuotaMap.put(userId, createReqVO.getHolidayBalance());
// -- 获取用户的假期表
Map<Long, HolidayUserDO> holidayUserDOMap = this.getHolidayUserMap(users, holidaySetting, holidayBalanceSettingDO);
Map<Long, HolidayUserDO> holidayUserDOMap = this.getHolidayUserMap(userIds, holidaySetting, holidayBalanceSettingDO);
List<HolidayUserRecordDO> newHolidayUserRecordDOList = new ArrayList<>();
List<HolidayUserDO> newHolidayUserDOList = new ArrayList<>();
String remark = myself.getNickname() + "" + targetUser.getNickname() + (createReqVO.getDirection() == 0 ? "增加" : "减去");
this.calculateUserHolidays(userQuotaMap, userId, holidayUserDOMap, holidaySetting, holidayBalanceSettingDO, newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, createReqVO.getDirection(), createReqVO.getReason());
for (AdminUserDO user : users) {
HolidayUserDO holidayUserDO = holidayUserDOMap.get(user.getId());
HolidayUserRecordDO holidayUserRecordDO = new HolidayUserRecordDO();
holidayUserRecordDO.setUserId(user.getId());
holidayUserRecordDO.setHolidayUserId(holidayUserDO.getId());
holidayUserRecordDO.setHolidaySettingId(holidaySetting.getId());
holidayUserRecordDO.setHolidayBalanceSettingId(holidayBalanceSettingDO.getId());
holidayUserRecordDO.setDirection(0);
holidayUserRecordDO.setHolidayBalance(userQuotaMap.get(user.getId()));
newHolidayUserRecordDOList.add(holidayUserRecordDO);
// --- 员工假期
newHolidayUserDOList.add(holidayUserDO.setHolidayBalance(
holidayUserRecordDO.getDirection() == 0 ? holidayUserDO.getHolidayBalance().add(holidayUserRecordDO.getHolidayBalance()) :
holidayUserDO.getHolidayBalance().subtract(holidayUserRecordDO.getHolidayBalance())
));
if (CollUtil.isNotEmpty(newHolidayUserRecordDOList)) {
holidayUserRecordMapper.insertBatch(newHolidayUserRecordDOList);
}
if (CollUtil.isNotEmpty(newHolidayUserDOList)) {
holidayUserMapper.insertOrUpdateBatch(newHolidayUserDOList);
}
if (createReqVO.getDirection() == 1) {
//减去用户记录中的剩余余额
List<HolidayUserRecordDO> editList = this.subHolidayUserRecord(userId, createReqVO.getHolidaySettingId(), createReqVO.getHolidayBalance());
if (CollUtil.isNotEmpty(editList)) {
holidayUserRecordMapper.updateBatch(editList);
}
}
}
private List<HolidayUserRecordDO> addHolidayUserRecord(Long userId, Long holidaySettingId, BigDecimal addAmount) {
List<HolidayUserRecordDO> editList = new ArrayList<>();
// -- 扣除用户记录中的余额 - 获取没有过期的余额列表 - 并且余额 > 0 - 按照过期时间升序 从最快过期的开始扣
List<HolidayUserRecordDO> holidayUserRecordDOS = holidayUserRecordMapper.selectList(new LambdaQueryWrapper<HolidayUserRecordDO>()
.eq(HolidayUserRecordDO::getUserId, userId)
.eq(HolidayUserRecordDO::getHolidaySettingId, holidaySettingId)
.orderByDesc(HolidayUserRecordDO::getExpiredTime)
);
// 过滤出不想等的 余额
holidayUserRecordDOS = holidayUserRecordDOS.stream().filter(record -> record.getRemainingBalance().compareTo(record.getHolidayBalance()) != 0).collect(Collectors.toList());
for (HolidayUserRecordDO record : holidayUserRecordDOS) {
BigDecimal remaining = record.getRemainingBalance();
BigDecimal holidayBalance = record.getHolidayBalance();
// 计算可以加到的金额
BigDecimal newBalance = remaining.add(addAmount);
if (newBalance.compareTo(holidayBalance) > 0) {
// 如果加上addAmount后超过holidayBalance
addAmount = newBalance.subtract(holidayBalance); // 计算需要继续加的部分
record.setRemainingBalance(holidayBalance); // 设置余额为holidayBalance
editList.add(record);
} else {
// 如果没有超过直接加上
record.setRemainingBalance(newBalance);
editList.add(record);
break; // 结束循环
}
}
return editList;
}
private List<HolidayUserRecordDO> subHolidayUserRecord(Long userId, Long holidaySettingId, BigDecimal subAmount) {
List<HolidayUserRecordDO> editList = new ArrayList<>();
// -- 扣除用户记录中的余额 - 获取没有过期的余额列表 - 并且余额 > 0 - 按照过期时间升序 从最快过期的开始扣
List<HolidayUserRecordDO> holidayUserRecordDOS = holidayUserRecordMapper.selectList(new LambdaQueryWrapper<HolidayUserRecordDO>()
.eq(HolidayUserRecordDO::getUserId, userId)
.eq(HolidayUserRecordDO::getHolidaySettingId, holidaySettingId)
.gt(HolidayUserRecordDO::getRemainingBalance, BigDecimal.ZERO)
.orderByAsc(HolidayUserRecordDO::getExpiredTime)
);
for (HolidayUserRecordDO record : holidayUserRecordDOS) {
BigDecimal remaining = record.getRemainingBalance();
if (remaining.compareTo(subAmount) >= 0) {
remaining = remaining.subtract(subAmount);
record.setRemainingBalance(remaining);
editList.add(record);
break; // 余额足够结束循环
} else {
subAmount = subAmount.subtract(remaining);
record.setRemainingBalance(BigDecimal.ZERO);
editList.add(record);
}
}
return editList;
}
@Override
public void createUserHoliday(CreateUserHolidayDTO dto) {
// -- 计算获取每个人的假期额度
AdminUserDO targetUser = adminUserService.getUser(dto.getUserId());
LocalDateTime now = LocalDateTime.now();
Map<Long, BigDecimal> userQuotaMap = new HashMap<>();
List<Long> userIds = Collections.singletonList(dto.getUserId());
HolidaySettingDO holidaySetting = holidaySettingService.getHolidaySetting(dto.getHolidaySettingId());
HolidayBalanceSettingDO holidayBalanceSettingDO = holidaySetting.getHolidayBalanceSettingDO();
userQuotaMap.put(dto.getUserId(), dto.getHolidayBalance());
// -- 获取用户的假期表
Map<Long, HolidayUserDO> holidayUserDOMap = this.getHolidayUserMap(userIds, holidaySetting, holidayBalanceSettingDO);
List<HolidayUserRecordDO> newHolidayUserRecordDOList = new ArrayList<>();
List<HolidayUserDO> newHolidayUserDOList = new ArrayList<>();
String remark = targetUser.getNickname() + "使用了 ";
this.calculateUserHolidays(userQuotaMap, dto.getUserId(), holidayUserDOMap, holidaySetting, holidayBalanceSettingDO, newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, dto.getDirection(), dto.getReason());
List<HolidayUserRecordDO> editList = new ArrayList<>();
if (dto.getDirection() == 1) {
//减去用户记录中的剩余余额
List<HolidayUserRecordDO> holidayUserRecordDOS = this.subHolidayUserRecord(dto.getUserId(), dto.getHolidaySettingId(), dto.getHolidayBalance());
editList.addAll(holidayUserRecordDOS);
} else {
//加上用户记录中的剩余余额
List<HolidayUserRecordDO> holidayUserRecordDOS = this.addHolidayUserRecord(dto.getUserId(), dto.getHolidaySettingId(), dto.getHolidayBalance());
editList.addAll(holidayUserRecordDOS);
}
if (CollUtil.isNotEmpty(editList)) {
holidayUserRecordMapper.updateBatch(editList);
}
if (CollUtil.isNotEmpty(newHolidayUserRecordDOList)) {
holidayUserRecordMapper.insertBatch(newHolidayUserRecordDOList);
@ -123,12 +199,210 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
}
}
@Override
public void beOverdue(List<HolidayUserRecordDO> holidayUserRecords) {
if (CollectionUtil.isEmpty(holidayUserRecords)) {
return;
}
List<Long> holidayUserIds = holidayUserRecords.stream().map(HolidayUserRecordDO::getHolidayUserId).distinct().collect(Collectors.toList());
List<HolidayUserDO> holidayUserDOS = holidayUserMapper.selectBatchIds(holidayUserIds);
Map<Long, HolidayUserDO> holidayUserDOMap = holidayUserDOS.stream().collect(Collectors.toMap(HolidayUserDO::getId, Function.identity()));
// -- 获取用户的假期表
Map<Long, List<HolidayUserRecordDO>> collect = holidayUserRecords.stream().collect(Collectors.groupingBy(HolidayUserRecordDO::getHolidayUserId));
List<HolidayUserDO> editList = new ArrayList<>();
for (Map.Entry<Long, List<HolidayUserRecordDO>> entry : collect.entrySet()) {
List<HolidayUserRecordDO> holidayUserRecordDOS = entry.getValue();
BigDecimal reduce = holidayUserRecordDOS.stream().map(HolidayUserRecordDO::getRemainingBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
HolidayUserDO holidayUserDO = holidayUserDOMap.get(entry.getKey());
BigDecimal holidayBalance = holidayUserDO.getHolidayBalance().add(reduce.negate());
holidayBalance = holidayBalance.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : holidayBalance;
holidayUserDO.setHolidayBalance(holidayBalance);
editList.add(holidayUserDO);
}
// --
holidayUserRecords.forEach(holidayUserRecordDO -> holidayUserRecordDO.setExpiredDeductionFlag(1));
holidayUserRecordMapper.updateBatch(holidayUserRecords);
if (CollUtil.isNotEmpty(editList)) {
holidayUserMapper.updateBatch(editList);
}
}
@Override
public List<HolidayUserRecordDO> getHolidayUserRecord(Long userId, Long holidaySettingId) {
return holidayUserRecordMapper.selectList(new LambdaQueryWrapper<HolidayUserRecordDO>()
.eq(HolidayUserRecordDO::getUserId, userId)
.eq(HolidayUserRecordDO::getHolidaySettingId, holidaySettingId)
.orderByDesc(HolidayUserRecordDO::getReleaseTime));
}
@Override
public PageResult<HolidayUserRecordDO> getHolidayUserRecordPage(HolidayUserRecordPageReqVO pageReqVO) {
return holidayUserRecordMapper.selectPage(pageReqVO);
}
@Override
public void init(HolidaySettingDO holidaySetting, List<HolidaySettingRangeDO> holidaySettingRangeDOS, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS) {
// -- 先查询出所有用户
List<AdminUserDO> users = this.getUsersByRange(holidaySetting, holidaySettingRangeDOS);
// -- 计算获取每个人的假期额度
Map<Long, Map<LocalDateTime, BigDecimal>> userQuotaMap = this.getQuotaAllMap(users, holidayBalanceSettingDO, holidayWorkingAgeDOS);
// -- 获取用户的假期表
List<Long> userIds = users.stream().map(AdminUserDO::getId).collect(Collectors.toList());
Map<Long, HolidayUserDO> holidayUserDOMap = this.getHolidayUserMap(userIds, holidaySetting, holidayBalanceSettingDO);
List<HolidayUserRecordDO> newHolidayUserRecordDOList = new ArrayList<>();
List<HolidayUserDO> newHolidayUserDOList = new ArrayList<>();
LocalDateTime now = LocalDateTime.now();
for (Long userId : userIds) {
String remark = "系统按照规则自动 增加";
this.calculateUserAllHolidays(userQuotaMap, userId, holidayUserDOMap, holidaySetting, holidayBalanceSettingDO, newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, 0, null);
}
// TODO: 2024/10/23 这里可能还会慢
if (CollUtil.isNotEmpty(newHolidayUserRecordDOList)) {
holidayUserRecordMapper.insertBatch(newHolidayUserRecordDOList);
}
if (CollUtil.isNotEmpty(newHolidayUserDOList)) {
holidayUserMapper.insertOrUpdateBatch(newHolidayUserDOList);
}
}
@Override
public void grant(HolidaySettingDO holidaySetting, List<HolidaySettingRangeDO> holidaySettingRangeDOS, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS) {
// -- 先查询出所有用户
List<AdminUserDO> users = this.getUsersByRange(holidaySetting, holidaySettingRangeDOS);
// -- 计算获取每个人的假期额度
Map<Long, BigDecimal> userQuotaMap = this.getQuotaMap(users, holidayBalanceSettingDO, holidayWorkingAgeDOS);
// -- 获取用户的假期表
List<Long> userIds = users.stream().map(AdminUserDO::getId).collect(Collectors.toList());
Map<Long, HolidayUserDO> holidayUserDOMap = this.getHolidayUserMap(userIds, holidaySetting, holidayBalanceSettingDO);
List<HolidayUserRecordDO> newHolidayUserRecordDOList = new ArrayList<>();
List<HolidayUserDO> newHolidayUserDOList = new ArrayList<>();
LocalDateTime now = LocalDateTime.now();
for (Long userId : userIds) {
String remark = "系统按照规则自动 增加";
this.calculateUserHolidays(userQuotaMap, userId, holidayUserDOMap, holidaySetting, holidayBalanceSettingDO, newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, 0, null);
}
// TODO: 2024/10/23 这里可能还会慢
if (CollUtil.isNotEmpty(newHolidayUserRecordDOList)) {
holidayUserRecordMapper.insertBatch(newHolidayUserRecordDOList);
}
if (CollUtil.isNotEmpty(newHolidayUserDOList)) {
holidayUserMapper.insertOrUpdateBatch(newHolidayUserDOList);
}
}
private List<AdminUserDO> getUsersByRange(HolidaySettingDO holidaySetting, List<HolidaySettingRangeDO> holidaySettingRangeDOS) {
List<AdminUserDO> users;
if (holidaySetting.getApplicationScope() == 0) {
users = adminUserService.getAllList(0, 1, null);
} else {
users = holidaySettingRangeService.getUsersByRange(holidaySettingRangeDOS);
}
return users;
}
private void calculateUserAllHolidays(Map<Long, Map<LocalDateTime, BigDecimal>> userQuotaMap, Long userId, Map<Long, HolidayUserDO> holidayUserDOMap,
HolidaySettingDO holidaySetting, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayUserRecordDO> newHolidayUserRecordDOList,
List<HolidayUserDO> newHolidayUserDOList, LocalDateTime now, String remark, Integer direction, String reason) {
Map<LocalDateTime, BigDecimal> stringBigDecimalMap = userQuotaMap.get(userId);
if (MapUtil.isNotEmpty(stringBigDecimalMap)) {
HolidayUserDO holidayUserDO = holidayUserDOMap.get(userId);
List<HolidayUserRecordDO> items = new ArrayList<>();
for (Map.Entry<LocalDateTime, BigDecimal> localDateTimeBigDecimalEntry : stringBigDecimalMap.entrySet()) {
HolidayUserRecordDO holidayUserRecordDO = new HolidayUserRecordDO();
holidayUserRecordDO.setUserId(userId);
holidayUserRecordDO.setHolidayUserId(holidayUserDO.getId());
holidayUserRecordDO.setHolidaySettingId(holidaySetting.getId());
holidayUserRecordDO.setHolidayBalanceSettingId(holidayBalanceSettingDO.getId());
holidayUserRecordDO.setDirection(direction);
holidayUserRecordDO.setHolidayBalance(localDateTimeBigDecimalEntry.getValue());
Map<Long, LocalDateTime> longLocalDateTimeMap = this.validityPeriodCalculation(localDateTimeBigDecimalEntry.getKey(), userId, holidayBalanceSettingDO);
LocalDateTime expiredTime = longLocalDateTimeMap.get(userId);
holidayUserRecordDO.setReleaseTime(localDateTimeBigDecimalEntry.getKey());
holidayUserRecordDO.setExpiredTime(expiredTime);
LocalDateTime expirationReminderTime = expiredTime == null ? null : expiredTime.minusDays(holidayBalanceSettingDO.getReminderTimeNum());
holidayUserRecordDO.setExpirationReminderTime(expirationReminderTime);
holidayUserRecordDO.setRemainingBalance(localDateTimeBigDecimalEntry.getValue());
holidayUserRecordDO.setRemark(remark + localDateTimeBigDecimalEntry.getValue() + (holidaySetting.getMinUnit() == 3 ? "小时" : "") + holidaySetting.getName());
holidayUserRecordDO.setReason(reason);
// -- 如果是0的话就不记录了
if (BigDecimal.ZERO.compareTo(holidayUserRecordDO.getHolidayBalance()) == 0) {
continue;
}
newHolidayUserRecordDOList.add(holidayUserRecordDO);
items.add(holidayUserRecordDO);
}
BigDecimal holidayBalance = holidayUserDO.getHolidayBalance().add(items.stream().filter(a -> a.getExpiredTime() == null || a.getExpiredTime().isAfter(now))
.map(product -> {
if (product.getDirection() == 0) {
return product.getHolidayBalance();
} else {
return product.getHolidayBalance().negate();
}
})
.reduce(BigDecimal.ZERO, BigDecimal::add));
// --- 员工假期
newHolidayUserDOList.add(
holidayUserDO.setHolidayBalance(
holidayBalance.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : holidayBalance
)
);
}
}
private void calculateUserHolidays(Map<Long, BigDecimal> userQuotaMap, Long userId, Map<Long, HolidayUserDO> holidayUserDOMap,
HolidaySettingDO holidaySetting, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayUserRecordDO> newHolidayUserRecordDOList,
List<HolidayUserDO> newHolidayUserDOList, LocalDateTime now, String remark, Integer direction, String reason) {
BigDecimal quota = userQuotaMap.get(userId);
// -- 如果是0的话就不记录了
if (BigDecimal.ZERO.compareTo(quota) == 0) {
return;
}
HolidayUserDO holidayUserDO = holidayUserDOMap.get(userId);
HolidayUserRecordDO holidayUserRecordDO = new HolidayUserRecordDO();
holidayUserRecordDO.setUserId(userId);
holidayUserRecordDO.setHolidayUserId(holidayUserDO.getId());
holidayUserRecordDO.setHolidaySettingId(holidaySetting.getId());
holidayUserRecordDO.setHolidayBalanceSettingId(holidayBalanceSettingDO.getId());
holidayUserRecordDO.setDirection(direction);
holidayUserRecordDO.setHolidayBalance(quota);
Map<Long, LocalDateTime> longLocalDateTimeMap = this.validityPeriodCalculation(now, userId, holidayBalanceSettingDO);
LocalDateTime expiredTime = longLocalDateTimeMap.get(userId);
if (direction == 0) {
holidayUserRecordDO.setReleaseTime(now);
holidayUserRecordDO.setExpiredTime(expiredTime);
LocalDateTime expirationReminderTime = expiredTime == null ? null : expiredTime.minusDays(holidayBalanceSettingDO.getReminderTimeNum());
holidayUserRecordDO.setExpirationReminderTime(expirationReminderTime);
holidayUserRecordDO.setExpirationReminderFlag(expirationReminderTime == null ? 1 : 0);
holidayUserRecordDO.setRemainingBalance(quota);
} else {
// -- 如果是扣除or提醒的话 这里直接是1 避免计算过期的时候再把他查出来
holidayUserRecordDO.setExpirationReminderFlag(1);
holidayUserRecordDO.setExpiredDeductionFlag(1);
}
holidayUserRecordDO.setRemark(remark + quota + (holidaySetting.getMinUnit() == 3 ? "小时" : "") + holidaySetting.getName());
holidayUserRecordDO.setReason(reason);
newHolidayUserRecordDOList.add(holidayUserRecordDO);
BigDecimal holidayBalance = holidayUserDO.getHolidayBalance().add(direction == 0 ? quota : quota.negate());
// --- 员工假期
newHolidayUserDOList.add(
holidayUserDO.setHolidayBalance(
holidayBalance.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : holidayBalance
)
);
}
@Override
public void clear(Long holidaySettingId, List<HolidaySettingRangeDO> holidaySettingRangeDOS) {
List<Long> userIds = new ArrayList<>();
if (CollUtil.isNotEmpty(holidaySettingRangeDOS)) {
userIds = holidaySettingRangeService.getUsersByRange(holidaySettingRangeDOS).stream().map(AdminUserDO::getId).collect(Collectors.toList());
}
if (CollUtil.isEmpty(userIds)) {
return;
}
// 清空请假数
holidayUserMapper.delete(new LambdaQueryWrapper<HolidayUserDO>()
.eq(HolidayUserDO::getHolidaySettingId, holidaySettingId)
@ -139,52 +413,255 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
.in(CollUtil.isNotEmpty(userIds), HolidayUserRecordDO::getUserId, userIds));
}
private Map<Long, HolidayUserDO> getHolidayUserMap(List<AdminUserDO> users, HolidaySettingDO holidaySetting, HolidayBalanceSettingDO holidayBalanceSettingDO) {
@Override
public void recalculateAssigned(RecalculateAssignedDTO dto) {
// 如果有变动 -
DetermineHolidayBalanceSettingSwitchVO settingSwitch = dto.getDetermineHolidayBalanceSettingSwitchVO();
if (settingSwitch.isChangeFlag()) {
if (settingSwitch.isSwitchFlag()) {
// 如果是开启状态 说明老的没开启 - 新的开启了 那么计算现有的人员即可 -
this.init(dto.getHolidaySetting(), dto.getPersonnelChangesVO().getNewAllList(), dto.getHolidayBalanceSetting(), dto.getHolidayWorkingAges());
} else {
// 如果关闭状态 - 则把所有老的都关闭 -
this.clear(dto.getHolidaySetting().getId(), dto.getPersonnelChangesVO().getOldAllList());
}
} else {
// -- 首先清空去除掉的人员
this.clear(dto.getHolidaySetting().getId(), dto.getPersonnelChangesVO().getDelList());
// -- 再处理现有的人员 - 这里可能就不是直接清空 - 而是记录 并且之前的请假记录要保留 - 不能应为改动了发放数据 而导致用户多出假期 -
// -- 3.假期发放方式调整 历史余额将会被清空 按新的方式重新发送
// -- 4.发放日期调整 修改发放日期后假期余额将按新规则重新计算
// -- 5.更改额度配置规则 修改余额发放方式后假期余额将按新规则重新发放
// -- 发放天数调整 - 不清空 - 只重新计算
if (settingSwitch.isAdjustTypeFlag() || settingSwitch.isDateAdjustFlag() || settingSwitch.isQuotaRuleFlag() || settingSwitch.isQuotaFlag() || CollUtil.isNotEmpty(dto.getPersonnelChangesVO().getSaveList())) {
this.clear(dto.getHolidaySetting().getId(), dto.getPersonnelChangesVO().getNewAllList());
this.init(dto.getHolidaySetting(), dto.getPersonnelChangesVO().getNewAllList(), dto.getHolidayBalanceSetting(), dto.getHolidayWorkingAges());
}
}
}
@Override
public Map<Long, LocalDateTime> validityPeriodCalculation(LocalDateTime now, List<Long> usersIds, HolidayBalanceSettingDO holidayBalanceSettingDO) {
Map<Long, LocalDateTime> map = new HashMap<>();
for (Long userId : usersIds) {
Map<Long, LocalDateTime> longLocalDateTimeMap = this.validityPeriodCalculation(now, userId, holidayBalanceSettingDO);
map.putAll(longLocalDateTimeMap);
}
return map;
}
@Override
public Map<Long, LocalDateTime> validityPeriodCalculation(LocalDateTime now, Long userId, HolidayBalanceSettingDO holidayBalanceSettingDO) {
LocalDateTime localDateTime = null;
Map<Long, LocalDateTime> map = new HashMap<>();
switch (holidayBalanceSettingDO.getValidityPeriod()) {
case 1:
localDateTime = now.plusMonths(1);
break;
case 2:
localDateTime = now.plusYears(1);
break;
case 3:
// 判断用户入职是否是闰年
boolean leap = now.getMonth() == Month.FEBRUARY
&& now.getDayOfMonth() == 29
&& Year.isLeap(now.getYear());
int dayOfMonth = now.getDayOfMonth();
// 如果是闰年的29号入职 并且当明年不是闰年 则日期 -1
if (leap && !Year.isLeap(now.plusYears(1).getYear())) {
dayOfMonth = dayOfMonth - 1;
}
localDateTime = now.plusYears(1).withMonth(now.getMonthValue()).withDayOfMonth(dayOfMonth);
break;
case 4:
localDateTime = now.with(TemporalAdjusters.lastDayOfYear());
break;
case 5:
if (StringUtils.isNotEmpty(holidayBalanceSettingDO.getFixedEveryYearInvalid())) {
try {
// 将当前年份设置到解析的日期上
localDateTime = LocalDateTime.parse(holidayBalanceSettingDO.getFixedEveryYearInvalid(), DateTimeFormatter.ofPattern("MM-dd")).withYear(now.getYear());
} catch (DateTimeParseException e) {
// -- 这里不做任何处理 - 如果日期格式错了那么就默认为null;
localDateTime = null;
}
}
break;
case 6:
localDateTime = null;
break;
case 7:
localDateTime = now.plusDays(holidayBalanceSettingDO.getFixedEveryMonthInvalid());
break;
case 8:
localDateTime = LocalDateTimeUtils.getQuarterEnd(now);
break;
default:
}
if (holidayBalanceSettingDO.getExtensionAllowedFlag() != null &&
holidayBalanceSettingDO.getExtensionAllowedFlag() == 1 && localDateTime != null) {
localDateTime = localDateTime.plusDays(holidayBalanceSettingDO.getExtendNum());
}
map.put(userId, localDateTime);
return map;
}
private Map<Long, HolidayUserDO> getHolidayUserMap(List<Long> userIds, HolidaySettingDO holidaySetting, HolidayBalanceSettingDO holidayBalanceSettingDO) {
// -- 先通过用户ids 获取列表
List<HolidayUserDO> holidayUserDOS = holidayUserMapper.selectList(new LambdaQueryWrapper<HolidayUserDO>()
.in(HolidayUserDO::getUserId, users.stream().map(AdminUserDO::getId).collect(Collectors.toList()))
.in(CollUtil.isNotEmpty(userIds), HolidayUserDO::getUserId, userIds)
.eq(HolidayUserDO::getHolidaySettingId, holidaySetting.getId())
.eq(HolidayUserDO::getHolidayBalanceSettingId, holidayBalanceSettingDO.getId()));
Map<Long, HolidayUserDO> holidayUserDOMap = holidayUserDOS.stream().collect(Collectors.toMap(HolidayUserDO::getUserId, holidayUserDO -> holidayUserDO));
for (AdminUserDO user : users) {
if (!holidayUserDOMap.containsKey(user.getId())) {
HolidayUserDO holidayUserDO = new HolidayUserDO(IdWorker.getId(), user.getId(), holidaySetting.getId(), holidayBalanceSettingDO.getId());
holidayUserDOMap.put(user.getId(), holidayUserDO);
for (Long userId : userIds) {
if (!holidayUserDOMap.containsKey(userId)) {
HolidayUserDO holidayUserDO = new HolidayUserDO(IdWorker.getId(), userId, holidaySetting.getId(), holidayBalanceSettingDO.getId());
holidayUserDOMap.put(userId, holidayUserDO);
}
}
return holidayUserDOMap;
}
/**
* 获取到用户假期额度
* 获取到用户假期额度 - 包含历史
*
* @param users
* @param holidayBalanceSettingDO
* @param holidayWorkingAgeDOS
* @return
*/
private Map<Long, BigDecimal> getQuotaMap(List<AdminUserDO> users, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS) {
Map<Long, BigDecimal> quotaMap = new HashMap<>();
if (holidayBalanceSettingDO.getQuotaRule() == 1) {
quotaMap = users.stream()
.collect(Collectors.toMap(AdminUserDO::getId, user -> new BigDecimal(holidayBalanceSettingDO.getQuota().toString()),
(oldValue, newValue) -> oldValue, // 解决重复键的问题
HashMap::new));
} else if (holidayBalanceSettingDO.getQuotaRule() == 2) {
Map<Integer, Integer> holidayWorkingAgeMap = holidayWorkingAgeDOS.stream().collect(Collectors.toMap(HolidayWorkingAgeDO::getYears, HolidayWorkingAgeDO::getNum));
LocalDateTime currentDate = LocalDateTime.now();
private Map<Long, Map<LocalDateTime, BigDecimal>> getQuotaAllMap(List<AdminUserDO> users, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS) {
Map<Long, Map<LocalDateTime, BigDecimal>> quotaMap = new HashMap<>();
LocalDateTime now = LocalDateTime.now();
// -- 自动发放只有按照每月固定的
if (holidayBalanceSettingDO.getType() == 1) {
for (AdminUserDO user : users) {
int years = Period.between(user.getEntryDate().toLocalDate(), currentDate.toLocalDate()).getYears();
Integer num = holidayWorkingAgeMap.get(years);
quotaMap.put(user.getId(), new BigDecimal(num.toString()));
if (user.getEntryDate() == null) {
continue;
}
List<LocalDateTime> theDayOfEachMonthSoFar = LocalDateTimeUtils.getTheDayOfEachMonthSoFar(user.getEntryDate(), now, holidayBalanceSettingDO.getIssueTimeType());
Map<LocalDateTime, BigDecimal> map = theDayOfEachMonthSoFar.stream()
.collect(Collectors.toMap(
localDateTime -> localDateTime,
localDateTime -> new BigDecimal(holidayBalanceSettingDO.getQuota().toString())
));
quotaMap.put(user.getId(), map);
}
} else if (holidayBalanceSettingDO.getType() == 2) {
for (AdminUserDO user : users) {
if (user.getEntryDate() == null) {
continue;
}
List<LocalDateTime> theDayOfEachMonthSoFar;
if (holidayBalanceSettingDO.getIssueTimeType() == 1) {
theDayOfEachMonthSoFar = LocalDateTimeUtils.getTheCurrentDateOfEachYearToACertainTime(user.getEntryDate(), now);
} else {
theDayOfEachMonthSoFar = LocalDateTimeUtils.getTheDayOfEachYeasSoFar(user.getEntryDate(), now);
}
if (holidayBalanceSettingDO.getQuotaRule() == 1) {
Map<LocalDateTime, BigDecimal> map = theDayOfEachMonthSoFar.stream()
.collect(Collectors.toMap(
localDateTime -> localDateTime,
localDateTime -> new BigDecimal(holidayBalanceSettingDO.getQuota().toString())
));
quotaMap.put(user.getId(), map);
} else {
Map<Integer, Integer> holidayWorkingAgeMap = holidayWorkingAgeDOS.stream().collect(Collectors.toMap(HolidayWorkingAgeDO::getYears, HolidayWorkingAgeDO::getNum));
Map<LocalDateTime, BigDecimal> map = new HashMap<>();
for (LocalDateTime localDateTime : theDayOfEachMonthSoFar) {
int years = Period.between(user.getEntryDate().toLocalDate(), localDateTime.toLocalDate()).getYears();
Integer num = holidayWorkingAgeMap.get(years);
map.put(localDateTime, new BigDecimal(num.toString()));
}
quotaMap.put(user.getId(), map);
}
}
} else {
// --- 如果都不是都话 默认为0
quotaMap = users.stream()
.collect(Collectors.toMap(AdminUserDO::getId, user -> BigDecimal.ZERO,
(oldValue, newValue) -> oldValue, // 解决重复键的问题
HashMap::new));
.collect(Collectors.toMap(
AdminUserDO::getId,
user -> Collections.singletonMap(now, BigDecimal.ZERO),
(oldValue, newValue) -> oldValue, // 保留第一个值
HashMap::new
));
}
return quotaMap;
}
/**
* 获取到用户假期额度 - (本次)
*
* @param users
* @param holidayBalanceSettingDO
* @param holidayWorkingAgeDOS
* @return
*/
@Override
public Map<Long, BigDecimal> getQuotaMap(List<AdminUserDO> users, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS) {
Map<Long, BigDecimal> quotaMap = new HashMap<>();
LocalDateTime now = LocalDateTime.now();
// -- 自动发放只有按照每月固定的
if (holidayBalanceSettingDO.getType() == 1) {
for (AdminUserDO user : users) {
if (user.getEntryDate() == null) {
continue;
}
quotaMap.put(user.getId(), new BigDecimal(holidayBalanceSettingDO.getQuota().toString()));
}
} else if (holidayBalanceSettingDO.getType() == 2) {
for (AdminUserDO user : users) {
if (user.getEntryDate() == null) {
continue;
}
if (holidayBalanceSettingDO.getQuotaRule() == 1) {
quotaMap.put(user.getId(), new BigDecimal(holidayBalanceSettingDO.getQuota().toString()));
} else {
Map<Integer, Integer> holidayWorkingAgeMap = holidayWorkingAgeDOS.stream().collect(Collectors.toMap(HolidayWorkingAgeDO::getYears, HolidayWorkingAgeDO::getNum));
int years = Period.between(user.getEntryDate().toLocalDate(), now.toLocalDate()).getYears();
Integer num = holidayWorkingAgeMap.get(years);
quotaMap.put(user.getId(), new BigDecimal(num.toString()));
}
}
} else {
// --- 如果都不是都话 默认为0
quotaMap = users.stream()
.collect(Collectors.toMap(
AdminUserDO::getId,
user -> BigDecimal.ZERO
));
}
return quotaMap;
}
@Override
public List<HolidayUserRecordDO> getHolidayBeOverdue(LocalDateTime now) {
return holidayUserRecordMapper.selectList(
new LambdaQueryWrapper<HolidayUserRecordDO>()
.gt(HolidayUserRecordDO::getRemainingBalance, 0)
.lt(HolidayUserRecordDO::getExpiredTime, now)
.eq(HolidayUserRecordDO::getExpiredDeductionFlag, 0)
);
}
@Override
public List<HolidayUserRecordDO> getHolidayRemind(LocalDateTime now) {
return holidayUserRecordMapper.selectList(
new LambdaQueryWrapper<HolidayUserRecordDO>()
.isNotNull(HolidayUserRecordDO::getExpirationReminderTime)
.gt(HolidayUserRecordDO::getRemainingBalance, 0)
.lt(HolidayUserRecordDO::getExpirationReminderTime, now)
.eq(HolidayUserRecordDO::getExpirationReminderFlag, 0)
);
}
@Override
public void editReminder(List<HolidayUserRecordDO> list) {
if (CollectionUtils.isEmpty(list)) {
return;
}
list.forEach(a -> a.setExpirationReminderFlag(1));
holidayUserRecordMapper.updateBatch(list);
}
}

View File

@ -60,4 +60,11 @@ public interface HolidayWorkingAgeService {
* @return
*/
List<HolidayWorkingAgeDO> selectBySettingId(Long settingId);
/**
* 根据假期设置ids获取列表
* @param holidaySettingIds
* @return
*/
List<HolidayWorkingAgeDO> selectBySettingIds(List<Long> holidaySettingIds);
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.service.holiday.holidayworkingage;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.controller.admin.holiday.holidayworkingage.vo.HolidayWorkingAgePageReqVO;
@ -11,6 +13,7 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
/**
@ -63,4 +66,13 @@ public class HolidayWorkingAgeServiceImpl implements HolidayWorkingAgeService {
.eq(HolidayWorkingAgeDO::getHolidaySettingId, settingId));
}
@Override
public List<HolidayWorkingAgeDO> selectBySettingIds(List<Long> holidaySettingIds) {
if (CollectionUtil.isEmpty(holidaySettingIds)) {
return Collections.emptyList();
}
return holidayWorkingAgeMapper.selectList(new LambdaQueryWrapper<HolidayWorkingAgeDO>()
.in(HolidayWorkingAgeDO::getHolidaySettingId, holidaySettingIds));
}
}

View File

@ -159,6 +159,13 @@ public interface AdminUserService {
*/
PageResult<AdminUserDO> getUserPage(UserPageReqVO reqVO);
/**
* 获取用户分页 - 带部门名称 -
* @param reqVO
* @return
*/
PageResult<AdminUserDO> getUserBringDeptPage(UserPageReqVO reqVO);
/**
* gps用户全量更新
*/

View File

@ -325,6 +325,14 @@ public class AdminUserServiceImpl implements AdminUserService {
return userMapper.selectPage(reqVO, getDeptCondition(reqVO.getDeptId()));
}
@Override
public PageResult<AdminUserDO> getUserBringDeptPage(UserPageReqVO reqVO) {
List<Long> deptIds = new ArrayList<>(getDeptCondition(reqVO.getDeptId()));
reqVO.setDeptIds(deptIds);
IPage<AdminUserDO> pageResult = userMapper.getUserBringDeptPage(MyBatisUtils.buildPage(reqVO), reqVO);
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
}
@Override
public void gpsFullUserUpdate() {
// 查询出所有带工厂id的部门ids

View File

@ -40,13 +40,13 @@ spring:
datasource:
master:
name: ruoyi-vue-pro-dev
url: jdbc:mysql://rm-bp1yloyj508qld78jno.mysql.rds.aliyuncs.com:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
url: jdbc:mysql://rm-bp1yloyj508qld78jno.mysql.rds.aliyuncs.com:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true&allowMultiQueries=true # MySQL Connector/J 8.X 连接的示例
driver-class-name: com.mysql.jdbc.Driver
username: root
password: Znalyrds2024
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
name: ruoyi-vue-pro-dev
url: jdbc:mysql://rm-bp1yloyj508qld78jno.mysql.rds.aliyuncs.com:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
url: jdbc:mysql://rm-bp1yloyj508qld78jno.mysql.rds.aliyuncs.com:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true&allowMultiQueries=true # MySQL Connector/J 8.X 连接的示例
driver-class-name: com.mysql.jdbc.Driver
username: root
password: Znalyrds2024

View File

@ -119,4 +119,40 @@
</if>
</where>
</select>
<select id="getUserBringDeptPage"
resultType="cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO">
select a.*,b.name as deptName
from system_users as a
left join system_dept as b on a.dept_id = b.id
<where>
a.deleted = 0
and a.user_type = 1
<if test="vo.username != null and vo.username != ''">
and a.username like concat('%', #{vo.username}, '%')
</if>
<if test="vo.nickName != null and vo.nickName != ''">
and a.nickname like concat('%', #{vo.nickName}, '%')
</if>
<if test="vo.mobile != null and vo.mobile != ''">
and a.mobile like concat('%', #{vo.mobile}, '%')
</if>
<if test="vo.status != null">
and a.status = #{vo.status}
</if>
<if test="vo.createTime != null and vo.createTime.length > 0">
<if test="vo.createTime[0] != null">
and a.create_time &gt;= #{vo.createTime[0]}
</if>
<if test="vo.createTime[1] != null">
and a.create_time &lt;= #{vo.createTime[1]}
</if>
</if>
<if test="vo.deptIds != null and vo.deptIds.size() > 0">
and a.dept_id in
<foreach collection="vo.deptIds" item="deptId" open="(" close=")" separator=",">
#{deptId}
</foreach>
</if>
</where>
</select>
</mapper>