commit
Some checks failed
API接口参数变更检测 / api-param-check (push) Has been cancelled

This commit is contained in:
2026-06-05 16:18:40 +08:00
parent 1ca34c6bb2
commit 3cba3bb74e
4393 changed files with 450030 additions and 103 deletions

View File

@@ -0,0 +1,215 @@
package jnpf.attendance.service.handle.chain;
import jnpf.attendance.service.filter.RuleFilter;
import jnpf.attendance.service.filter.RuleFilterContext;
import jnpf.attendance.service.filter.RuleFilterResult;
import jnpf.base.UserInfo;
import jnpf.entity.attendance.AttendanceRuleScope;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.v2.WorkBoundaryCoverageEnum;
import jnpf.model.attendance.vo.attendance.OvertimeRuleVo;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
/**
* 出勤规则过滤链执行器
*
* @author yanwenfu
* @create 2025-09-25
*/
@Component
public class RuleFilterChain {
private final List<RuleFilter> filters;
public RuleFilterChain(List<RuleFilter> filters) {
// 按照 getOrder 排序,保证执行顺序
this.filters = filters.stream()
.sorted(Comparator.comparingInt(RuleFilter::getOrder))
.collect(Collectors.toList());
}
/**
* 获取今日可打卡出勤规则+数据填写
* @param curDate 当前日期
* @param ruleList 出勤规则列表(当前+前一天)
* @param map k:用户id, v:加班规则
* @param userInfo 用户信息
* @return java.util.List<jnpf.entity.attendance.FtbAttendanceDailyRule>
*/
public List<FtbAttendanceDailyRule> execute(Date curDate, List<FtbAttendanceDailyRule> ruleList, Map<String, OvertimeRuleVo> map, UserInfo userInfo) {
RuleFilterContext context = new RuleFilterContext(curDate, ruleList, map);
stop : for (FtbAttendanceDailyRule rule : ruleList) {
boolean keep = false;
for (RuleFilter filter : filters) {
RuleFilterResult result = filter.keepRule(rule, context, userInfo);
if (result.isTerminate()) {
// 终止整个责任链
break stop;
}
if (result.isKeep()) {
// 不保留,但继续走
keep = true;
break;
}
}
if (keep) {
context.getCollectList().add(rule);
}
}
// 填值
if (context.getCollectList().isEmpty()) {
return new ArrayList<>();
}
// 去除半天休
List<String> restRuleList = context.getCollectList().stream()
.filter(v -> DateDetail.checkSameDay(context.getCurDate(), v.getDay()) && v.getAttendanceType().equals(AttendanceTypeEnum.REST.getCode()))
.map(FtbAttendanceDailyRule::getId)
.collect(Collectors.toList());
long count = context.getCollectList().stream().filter(v -> DateDetail.checkSameDay(context.getCurDate(), v.getDay())).count();
if (!restRuleList.isEmpty() && count > 1) {
context.getCollectList().removeIf(v -> restRuleList.contains(v.getId()));
}
// 今日所有需要打卡的出勤规则
List<FtbAttendanceDailyRule> addList = new ArrayList<>();
context.getCollectList().forEach(rule -> {
if (rule.getAttendanceType().equals(AttendanceTypeEnum.BUSINESS_TRIP.getCode()) || rule.getAttendanceType().equals(AttendanceTypeEnum.STEP_OUT.getCode())) {
// 外出或出差, 且无班次则设置班次类型为-1
rule.setAttendanceType(AttendanceTypeEnum.DEFAULT.getCode());
rule.setInStepOutType(ConstantUtil.NUM_TRUE);
rule.setOutStepOutType(ConstantUtil.NUM_TRUE);
}
// 普通班次 且 允许无需审批的加班 缺卡时间延后 与加班下班相同
if (rule.getAttendanceType().equals(AttendanceTypeEnum.ORDINARY.getCode()) && rule.getOvertime().equals(ConstantUtil.NUM_TRUE)) {
outLackSet(rule, context);
}
// 请假
if (rule.getInUnbounded().equals(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode())) {
rule.setMsg("请假回岗");
// rule.setInLackPoint(rule.getInPoint());
}
if (rule.getOutUnbounded().equals(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode())) {
rule.setMsg("请假离岗");
// rule.setOutLackPoint(rule.getOutPoint());
}
// 借调
if (rule.getInUnbounded().equals(WorkBoundaryCoverageEnum.SECONDMENT_COVERED.getCode())) {
rule.setInHideStatus(ConstantUtil.STR_TRUE);
// 在这个时间点生成无需打卡 -2
rule.setOnWorkIgnore(true);
rule.setInLackPoint(rule.getInPoint());
}
if (rule.getOutUnbounded().equals(WorkBoundaryCoverageEnum.SECONDMENT_COVERED.getCode())) {
rule.setOutHideStatus(ConstantUtil.STR_TRUE);
// 在这个时间点生成无需打卡 -2
rule.setOffWorkIgnore(true);
rule.setOutLackPoint(rule.getOutPoint());
}
// 加班
if (rule.getInUnbounded().equals(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode())) {
rule.setInHideStatus(ConstantUtil.STR_TRUE);
// 在这个时间点生成无需打卡 -2
rule.setOnWorkIgnore(true);
rule.setClockStartPoint(rule.getInPoint());
rule.setInLackPoint(rule.getInPoint());
setAnother(ConstantUtil.ON_WORK, context, rule, addList);
}
if (rule.getOutUnbounded().equals(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode())) {
rule.setOutHideStatus(ConstantUtil.STR_TRUE);
// 在这个时间点生成无需打卡 -2
rule.setOffWorkIgnore(true);
rule.setOutLackPoint(rule.getOutPoint());
setAnother(ConstantUtil.OFF_WORK, context, rule, addList);
}
// 晚走晚到
if (rule.getInUnbounded().equals(WorkBoundaryCoverageEnum.LATE_LEAVE_LATE_ARRIVE.getCode())) {
// 在这个时间点生成无需打卡 -2
rule.setOnWorkIgnore(true);
}
if (rule.getOutUnbounded().equals(WorkBoundaryCoverageEnum.LATE_LEAVE_LATE_ARRIVE.getCode())) {
// 在这个时间点生成无需打卡 -2
rule.setOffWorkIgnore(true);
}
if (rule.getAttendanceType().equals(AttendanceTypeEnum.WORKOVERTIME.getCode())) {
// 按审批时长申请计算 无需打卡
if (rule.getOvertimeRuleDetail().getCalcMethod().equals(1)) {
rule.setOnWorkIgnore(true);
rule.setOffWorkIgnore(true);
}
// 查询上一个班次的下班时间
inLackSet(rule, context);
// 查询下一个班次的上班时间
outLackSet(rule, context);
}
});
context.getCollectList().addAll(addList);
context.getCollectList().sort(
Comparator.comparing(
FtbAttendanceDailyRule::getInPoint,
Comparator.nullsLast(Comparator.naturalOrder())
)
);
return context.getCollectList();
}
private void outLackSet(FtbAttendanceDailyRule rule, RuleFilterContext context) {
// 加班 或 普班无审批加班
if (null == rule.getOutLackPoint() || (rule.getAttendanceType().equals(AttendanceTypeEnum.ORDINARY.getCode()) && rule.getOvertime().equals(ConstantUtil.NUM_TRUE))) {
if (rule.getRn() - 1 > 0) {
FtbAttendanceDailyRule nextRule = context.getRuleList().get(rule.getRn() - 2);
if (null != nextRule.getInPoint()) {
rule.setOutLackPoint(nextRule.getInPoint());
} else {
if (!DateDetail.checkSameDay(rule.getDay(), context.getCurDate()) && DateDetail.checkSameDay(rule.getOutPoint(), context.getCurDate())) {
// 昨天的班下班时间在今天, 所以缺卡时间最多到今晚24点
rule.setOutLackPoint(DateDetail.endOfDay(rule.getOutPoint()));
} else {
rule.setOutLackPoint(DateDetail.getNextDay(rule.getOutPoint()));
}
}
} else {
// 无下一个班次 暂时设置为24小时后, 明天会重新获取
rule.setOutLackPoint(DateDetail.getNextDay(rule.getOutPoint()));
}
}
}
private void inLackSet(FtbAttendanceDailyRule rule, RuleFilterContext context) {
if (null == rule.getInLackPoint()) {
if (rule.getRn() + 1 < context.getRuleList().size()) {
FtbAttendanceDailyRule dailyRule = context.getRuleList().get(rule.getRn());
rule.setClockStartPoint(null == dailyRule.getOutPoint() ? DateDetail.beginOfDay(rule.getInPoint()) : dailyRule.getOutPoint());
} else {
// 无上一个班次 设置为上班时间的0点
rule.setClockStartPoint(DateDetail.beginOfDay(rule.getInPoint()));
}
rule.setInLackPoint(rule.getOutPoint());
}
}
/**
* 设置无需打卡时间
*/
private void setAnother(Integer workStatus, RuleFilterContext context, FtbAttendanceDailyRule rule, List<FtbAttendanceDailyRule> addList) {
FtbAttendanceDailyRule dailyRule = context.getMap().get(rule.getId());
if (null != dailyRule) {
FtbAttendanceDailyRule r = context.getCollectList().stream().filter(v -> v.getId().equals(dailyRule.getId())).findFirst().orElse(null);
if (null == r) {
if (workStatus.equals(ConstantUtil.ON_WORK)) {
dailyRule.setOutHideStatus(ConstantUtil.STR_TRUE);
dailyRule.setOffWorkIgnore(true);
} else {
dailyRule.setInHideStatus(ConstantUtil.STR_TRUE);
dailyRule.setOnWorkIgnore(true);
}
addList.add(dailyRule);
}
}
}
}

View File

@@ -0,0 +1,214 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceUserSettingService;
import jnpf.base.UserInfo;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.*;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.ShiftChangModel;
import jnpf.model.attendance.vo.attendance.ApproveBaseImVo;
import jnpf.model.attendance.vo.attendance.ApproveImVo;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.vo.UserSettingVo;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.DateDetail;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* @Author huanglinpan
* @Date 2024/8/12 10:58
* @Version 1.0 (版本号)
*/
@Component(AttendanceConstant.APPROVE)
@Slf4j
public class AttendanceApproveNotice implements AttendanceNotice<ApproveBaseImVo,ApproveImVo>{
@Resource
private AttendanceUserSettingService attendanceUserSettingService;
@Override
public Boolean isPass(ApproveImVo approveImVo) {
if (!approveImVo.getAttendanceNoticeEnum().equals(AttendanceNoticeEnum.APPROVE) && !approveImVo.getAttendanceNoticeEnum().equals(AttendanceNoticeEnum.JOIN_GROUP)) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public List<ApproveBaseImVo> generatingData(ApproveImVo approveImVo) {
List<ApproveBaseImVo> list = new ArrayList<>();
list.add(approveImVo.getApproveBaseImVo());
return list;
}
@Override
public List<String> getRecipient(ApproveImVo approveImVo) {
List<String> list = checkSetting(approveImVo.getUserIds(),UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE.getCode());
if(null != approveImVo.getType() && Objects.equals(AttendanceNoticeEnum.JOIN_GROUP.getCode(), approveImVo.getType())) {
// 处理被借调人信息
return checkSetting(list,UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_JOIN_LEAVE_REMINDER.getCode());
}
return list;
}
@NotNull
private List<String> checkSetting(List<String> userIds, String code) {
// 校验接收人是否打开配置
List<UserSettingVo> settingList = attendanceUserSettingService.getSettingList(userIds, UserSettingTypeEnum.USER.getCode(), code);
Map<String, UserSettingVo> map = settingList.stream().collect(Collectors.toMap(UserSettingVo::getAssociationId, Function.identity()));
List<String> list = new ArrayList<>();
userIds.forEach(id -> {
UserSettingVo userSettingVo = map.get(id);
if (null == userSettingVo) {
list.add(id);
}else {
// 检查是否打开
if (1 == userSettingVo.getStatus()) {
list.add(id);
}
}
});
return list;
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(ApproveImVo approveImVo, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
// 特殊处理借调审批被借调用户看到的URL的参数
log.error("noticeId:{},approveImVo.getApproveBaseImVo().getUrl():{}",noticeId,approveImVo.getApproveBaseImVo().getUrl());
String url = APPROVE_SECONDED_URL.equals(approveImVo.getApproveBaseImVo().getUrl()) ? String.format(APPROVE_SECONDED_URL, noticeId) : approveImVo.getApproveBaseImVo().getUrl();
log.error("url:{}",url);
objects.add(JumpUrl.builder().url(url).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
return SystemNoticeStrategy.builder()
.title(approveImVo.getApproveBaseImVo().getTitle())
.noticeModuleEnum(NoticeModuleEnum.KQ_SP)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<ApproveBaseImVo> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
ApproveBaseImVo approveBaseImVo = data.get(0);
// 通过/拒绝的消息有操作者
String startStr = null != approveBaseImVo.getCreateUserName() ? "操作者:" + approveBaseImVo.getCreateUserName() + "</br>": "";
if (Objects.equals(ApprovalSettingTypeEnum.LEAVE.getCode(), approveBaseImVo.getType())){
//开始时间2024年5月16日 16:23
//结束时间2024年5月17日 09:00
// 考勤V1.6 加入请假类型 小时类维持以上不变,天类: 开始时间2024年5月16日 结束时间2024年5月17日 半天类2024年5月16日 上半天 结束时间2024年5月17日 下半天
Integer unit = approveBaseImVo.getUnit();
if (LeaveUnitEnum.HOUR.getCode().equals(unit)){
return startStr +
"开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd HH:mm") + "</br>" +
"结束时间:" + DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd HH:mm");
}else if (LeaveUnitEnum.DAY.getCode().equals(unit)){
return startStr +
"开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd") + "</br>" +
"结束时间:" + DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd");
}else {
return startStr +
"开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd ") + dayStr(approveBaseImVo.getStartTimeType()) + "</br>" +
"结束时间:" + DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd ")+ dayStr(approveBaseImVo.getEndTimeType());
}
}
if (Objects.equals(ApprovalSettingTypeEnum.OVERTIME.getCode(), approveBaseImVo.getType())){
//选择日期2024年5月16日
//开始时间22:00
//结束时间次日08:00
// 结束时间次日处理
StringBuffer end = new StringBuffer();
if (!DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd").equals(DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd"))){
end.append("次日");
}
end.append(DateUtil.format(approveBaseImVo.getEndTime(), "HH:mm")).append("</br>");
return startStr +
"选择日期:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd") + "</br>" +
"开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "HH:mm") + "</br>" +
"结束时间:" + end;
}
if (Objects.equals(ApprovalSettingTypeEnum.GO_OUT.getCode(), approveBaseImVo.getType())){
//开始时间2024年5月16日
//结束时间2024年5月17日
//时长2天
return startStr +
"开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd") + "</br>" +
"结束时间:" + DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd") + "</br>" +
"时长:" + approveBaseImVo.getDuration();
}
if (Objects.equals(ApprovalSettingTypeEnum.BUSINESS_TRIP.getCode(), approveBaseImVo.getType())){
// 出发地:地点名称地点名称地点名称地点名称
//目的地:地点名称地点名称地点名称地点名称
return startStr +
"出发地:" + approveBaseImVo.getDeparture() + "</br>" +
"目的地:" + approveBaseImVo.getDestination();
}
if (Objects.equals(ApprovalSettingTypeEnum.SECONDED.getCode(), approveBaseImVo.getType())){
//借调开始时间2024年5月16日 16:23
//借调结束时间2024年5月17日 09:00
//借调考勤组:小露测试考勤组
//被借调考勤组:小露验收考勤组
return startStr +
"借调开始时间:" + DateUtil.format(approveBaseImVo.getStartTime(), "yyyy-MM-dd HH:mm") + "</br>" +
"借调结束时间:" + DateUtil.format(approveBaseImVo.getEndTime(), "yyyy-MM-dd HH:mm") + "</br>" +
"借调考勤组:" + approveBaseImVo.getGroupName() + "</br>" +
"被借调考勤组:" + approveBaseImVo.getSecondedGroupName();
}
if (Objects.equals(ApprovalSettingTypeEnum.OUT.getCode(), approveBaseImVo.getType())) {
return startStr
+ "发起时间:" + DateDetail.getDate2Str(approveBaseImVo.getCreateTime(), DateDetail.DF20) + "</br>"
+ "考勤点:" + approveBaseImVo.getAddress();
}
if (Objects.equals(ApprovalSettingTypeEnum.ROUTINE.getCode(), approveBaseImVo.getType())) {
String str = startStr + "补卡时间:" + approveBaseImVo.getRuleTime() + "</br>";
if (StringUtils.isEmpty(startStr)) {
str += "出勤结果:" + approveBaseImVo.getResult();
}
return str;
}
if (Objects.equals(ApprovalSettingTypeEnum.ACTION_RESULT.getCode(), approveBaseImVo.getType())) {
return startStr
+ "变更人员:" + approveBaseImVo.getSecondedUsersName() + "</br>"
+ "变更时间:" + approveBaseImVo.getRuleTime() + "</br>"
+ "出勤结果:" + approveBaseImVo.getAfterResult() + "</br>"
+ "处理结果:" + approveBaseImVo.getResult();
}
return null;
}
private static String dayStr(Integer type) {
if (1 == type){
return "上半天";
}else {
return "下半天";
}
}
}

View File

@@ -0,0 +1,128 @@
package jnpf.attendance.service.handle.notice;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.mapper.AttendanceDailyRuleMapper;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.AttendanceChangeModel;
import jnpf.model.attendance.model.AttendanceChangeNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import jnpf.util.StringUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* 考勤变更(不审批)
*
* @author yanwenfu
* @create 2024-08-16
*/
@Service(value = AttendanceConstant.CHECK_RESULT_CHANGE)
public class AttendanceChangeNotice implements AttendanceNotice<AttendanceChangeModel, AttendanceChangeNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Resource
private AttendanceDailyRuleMapper attendanceDailyRuleMapper;
@Resource
private UserAntifreeze userAntifreeze;
@Override
public Boolean isPass(AttendanceChangeNoticeModel model) {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_RESULT_CHANGE_REMINDER);
}
@Override
public List<AttendanceChangeModel> generatingData(AttendanceChangeNoticeModel model) {
List<PartUserInfoVo> list = userAntifreeze.getAllByIds(List.of(model.getHandleUserId()), model.getTenantId());
PartUserInfoVo user = list.stream().findFirst().orElse(null);
StringBuilder handelUser = new StringBuilder();
if (Objects.isNull(user)) {
handelUser.append("");
} else {
handelUser.append(user.getRealName()).append("(").append(
StringUtil.isEmpty(user.getOrganizeName()) ? "暂无" : user.getOrganizeName()).append("-").append(
StringUtil.isEmpty(user.getPositionName()) ? "暂无" : user.getPositionName()).append(")");
}
FtbAttendanceDailyRule dailyRule = attendanceDailyRuleMapper.selectById(model.getRuleId());
String changeTime;
if (null == dailyRule) {
changeTime = "--";
} else {
changeTime = model.getClockInType().equals(ConstantUtil.ON_WORK) ? DateDetail.getDate2Str(dailyRule.getInPoint(), DateDetail.DF9) : DateDetail.getDate2Str(dailyRule.getOutPoint(), DateDetail.DF9);
}
AttendanceChangeModel attendanceChangeModel = AttendanceChangeModel.builder()
.handelUser(handelUser.toString())
.changeTime(null == dailyRule ? "--" : changeTime)
.changeResult(getResult(model.getChangeType()))
.build();
return List.of(attendanceChangeModel);
}
private String getResult(Integer changeType) {
// 变更类型(-1: 缺卡, 1: 正常, 2: 迟到, 3: 早退, 99: 撤回变更)
switch (changeType) {
case -1:
return "缺卡";
case 1:
return "正常";
case 2:
return "迟到";
case 3:
return "早退";
case 99:
return "撤回变更";
default:
return "--";
}
}
@Override
public List<String> getRecipient(AttendanceChangeNoticeModel model) {
return List.of(model.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(AttendanceChangeNoticeModel model, String noticeId) {
List<JumpUrl> list = new ArrayList<>();
list.add(new JumpUrl(String.format(AttendanceConstant.GROUP_LOCK_URL1, model.getHandleUserId()), AttendanceConstant.GROUP_LOCK_BUTTON_NAME1, AttendanceConstant.COLOR_BLACK,3,"contactInfo", JSON.toJSONString(new JSONObject(){{
put("contactId", model.getHandleUserId());
}})));
return SystemNoticeStrategy.builder()
.title(AttendanceConstant.TITLE_CLOCK_IN_CHANGE)
.noticeModuleEnum(NoticeModuleEnum.CQJG_BD)
.jumpUrls(list)
.build();
}
@Override
public String getContext(List<AttendanceChangeModel> dataList) {
if (null == dataList || dataList.isEmpty()) {
return "";
}
AttendanceChangeModel model = dataList.get(0);
return "操作人:" + model.getHandelUser() + "</br>"
+ "变更记录:" + model.getChangeTime() + "</br>"
+ "变更结果:" + model.getChangeResult();
}
}

View File

@@ -0,0 +1,53 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.base.UserInfo;
import jnpf.model.attendance.model.AttendanceNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Objects;
/**
*
* @param <T> 作为详情展示及IM消息内容的实体
*/
public interface AttendanceNotice<T, V extends AttendanceNoticeModel> {
/**
* 通过当前通知发送的条件实现(前置条件)
* @param attendanceNoticeModel
* @return
*/
Boolean isPass(V attendanceNoticeModel);
/**
* 生成记录数据用于详情及im消息展示
* @param attendanceNoticeModel 过程数据
* @return
*/
List<T> generatingData(V attendanceNoticeModel);
/**
* 设置接收人
* @param attendanceNoticeModel 过程数据
*/
List<String> getRecipient(V attendanceNoticeModel);
/**
* 设置系统通知策略
* @param attendanceNoticeModel 过程数据
* @return
*/
SystemNoticeStrategy setSystemNoticeStrategy(V attendanceNoticeModel, String noticeId);
/**
* 设置im通知内容部分如需要请使用/br换行
* @param data 详情展示及IM消息内容的实体集合
* @return
*/
String getContext(List<T> data);
}

View File

@@ -0,0 +1,265 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import jnpf.ImRobotApi;
import jnpf.attendance.mapper.AttendanceManagerPermissionMapper;
import jnpf.attendance.service.AttendanceNoticeService;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.attendance.service.AttendanceUserSettingService;
import jnpf.base.ActionResult;
import jnpf.entity.AttendanceGroupUser;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.enums.attendance.UserSettingTypeEnum;
import jnpf.from.*;
import jnpf.model.attendance.dto.NoticeSaveDto;
import jnpf.model.attendance.model.AttendanceNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.NoticeConfirm;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.vo.AttendanceGroupAdminVo;
import jnpf.model.attendance.vo.AttendancePermissionVo;
import jnpf.model.attendance.vo.UserSettingVo;
import jnpf.util.ConstantUtil;
import jnpf.util.RandomUtil;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
@Component
@Slf4j
public class AttendanceNoticeHandler {
@Autowired
private Map<String, AttendanceNotice> attendanceNoticeList;
@Autowired
private AttendanceNoticeService attendanceNoticeService;
@Autowired
private ImRobotApi imRobotApi;
@Autowired
private AttendanceUserSettingService attendanceUserSettingService;
@Resource
private AttendanceManagerPermissionMapper attendanceManagerPermissionMapper;
@Autowired
private AttendanceUserService attendanceUserService;
/**
* 通知发送
* @param attendanceNoticeModel 过程数据
*/
public void send(AttendanceNoticeModel attendanceNoticeModel) {
if (Objects.isNull(attendanceNoticeModel.getAttendanceNoticeEnum())) {
log.error("通知类型未填充");
return;
}
AttendanceNotice notice = attendanceNoticeList.get(attendanceNoticeModel.getAttendanceNoticeEnum().getServiceName());
if (Objects.isNull(notice)) {
log.error("未获取到该通知[{}]具体service实现", attendanceNoticeModel.getAttendanceNoticeEnum().getDesc());
return;
}
if (!notice.isPass(attendanceNoticeModel)) {
log.error("未满足通知[{}]条件,过滤", attendanceNoticeModel.getAttendanceNoticeEnum().getDesc());
return;
}
List<T> data = notice.generatingData(attendanceNoticeModel);
if(CollUtil.isEmpty(data)){
return;
}
List<String> recipientList = notice.getRecipient(attendanceNoticeModel);
if (CollUtil.isEmpty(recipientList)) {
log.error("未获取到该通知[{}]接收人", attendanceNoticeModel.getAttendanceNoticeEnum().getDesc());
return;
}
String noticeId = RandomUtil.uuId();
SystemNoticeStrategy build = notice.setSystemNoticeStrategy(attendanceNoticeModel, noticeId);
Integer isConfirm = Objects.nonNull(build.getIsConfirm()) && build.getIsConfirm() ? 1 : 0;
attendanceNoticeService.noticeSave(NoticeSaveDto.builder()
.dataJson(JSON.toJSONString(data))
.id(noticeId)
.title(build.getTitle())
.isConfirm(isConfirm)
.type(attendanceNoticeModel.getAttendanceNoticeEnum())
.userId(UserProvider.getLoginUserId())
.confirmList(Objects.equals(isConfirm, 0) ? null : JSON.toJSONString(initNoticeConfirm(recipientList)))
.build());
sendNotice(attendanceNoticeModel.getTenantId(), notice.getContext(data), build, isConfirm, recipientList, noticeId, attendanceNoticeModel.getModuleId());
}
private void sendNotice(String tenantId, String context, SystemNoticeStrategy systemNoticeStrategy, Integer isConfirm, List<String> recipientList, String noticeId,String moduleId) {
if (CollUtil.isEmpty(recipientList)) {
log.error("考勤发送系统通知记录id[{}],接收人为空", noticeId);
return;
}
SingleSendRobotNoticeForm form = new SingleSendRobotNoticeForm();
form.setRobotTypeEnum(ImRobotTypeEnum.FTB_XZS);
form.setMessageAttributionRobotMpId(MP_ID);
form.setToUserIds(recipientList);
form.setTenantId(tenantId);
SendRobotNoticeDataForm robotNoticeDataForm = new SendRobotNoticeDataForm();
robotNoticeDataForm.setLogo(ATTENDANCE_APP_LOGO);//固定图片
robotNoticeDataForm.setAppName(systemNoticeStrategy.getNoticeModuleEnum().getMsg());
robotNoticeDataForm.setTitle(systemNoticeStrategy.getTitle());
robotNoticeDataForm.setContent(context);
robotNoticeDataForm.setContentSummary(systemNoticeStrategy.getTitle());
LinkedList<JumpUrlListModel> objects = CollUtil.newLinkedList();
if (Objects.equals(isConfirm, 1)) {
objects.add(JumpUrlListModel.builder()
.displayMethodEnum(JumpUrlListModel.DisplayMethodEnum.FALSE)
.reqMethod(JumpUrlListModel.ReqMethodEnum.GET)
.type(1)
.url(String.format(ATTENDANCE_NOTICE_CONFIRM_LIST_VIEW_URL, noticeId))
.buttonName(ATTENDANCE_NOTICE_CONFIRM_LIST_BUTTON_NAME)
.mpId(MP_ID)
.buttonColor("#1A1A1A")
.build());
objects.add(JumpUrlListModel.builder()
.type(2)
.isConfirm(1)
.confirmButton(ConfirmButton.builder().status(1)
.buttName1("确认收到")
.color1("#3C6DF8")
.url1(String.format(ATTENDANCE_NOTICE_CONFIRM_URL, noticeId))
.buttName2("已收到")
.color2("#D9D9DB")
.url2("")
.build())
.displayMethodEnum(JumpUrlListModel.DisplayMethodEnum.FALSE)
.reqMethod(JumpUrlListModel.ReqMethodEnum.POST)
.buttonName(ATTENDANCE_NOTICE_CONFIRM)
.url("")
.build());
} else {
List<JumpUrl> jumpUrls = systemNoticeStrategy.getJumpUrls();
if (CollUtil.isEmpty(jumpUrls)) {
log.error("考勤发送系统通知记录id[{}],未设置按钮事件", noticeId);
return;
}
int size = jumpUrls.size();
jumpUrls.forEach(jumpUrl -> objects.add(JumpUrlListModel.builder()
.reqMethod(JumpUrlListModel.ReqMethodEnum.GET)
.displayMethodEnum(size > 1 ? JumpUrlListModel.DisplayMethodEnum.FALSE : JumpUrlListModel.DisplayMethodEnum.TRUE)
.type(Objects.isNull(jumpUrl.getType()) ? 1 : jumpUrl.getType())
.url(jumpUrl.getUrl())
.mpId(StringUtil.isNotBlank(jumpUrl.getMpId()) ? jumpUrl.getMpId() : MP_ID)
.buttonName(jumpUrl.getUrlName())
.buttonColor(jumpUrl.getColor())
.nativeUrl(Objects.isNull(jumpUrl.getType()) ? null : NativeUrl.builder()
.page(jumpUrl.getPage())
.param(jumpUrl.getParam())
.build())
.build()));
}
robotNoticeDataForm.setJumpUrlList(objects);
form.setRobotNoticeDataForm(robotNoticeDataForm);
// log.error("打印消息内容form:{}", JSON.toJSONString(form));
ActionResult actionResult = imRobotApi.sendSingleRobotNotice(form);
}
private List<NoticeConfirm> initNoticeConfirm(List<String> recipientList) {
return recipientList.stream().map(userId -> NoticeConfirm.builder().userId(userId).confirmedTime(new Date()).isConfirmed(0).build()).collect(Collectors.toList());
}
public List<String> getRecipientForSelfAndChild(String groupId, Boolean isAdmin) {
List<String> selfAndChildrenGroupIds = CollUtil.newArrayList(groupId);
if (isAdmin) {
List<AttendanceGroupAdminVo> attendanceGroupAdminVos = attendanceManagerPermissionMapper.queryGroupUsers(selfAndChildrenGroupIds);
List<String> adminUserIds = attendanceGroupAdminVos.stream().map(AttendanceGroupAdminVo::getUserId).collect(Collectors.toList());
if (CollUtil.isEmpty(adminUserIds)) {
return Collections.emptyList();
}
return getUserIdsForFilterStatus(adminUserIds, UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE, UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_RULE_CHANGE_REMINDER);
}
Date date = new Date();
List<AttendanceGroupUser> attendanceGroupUsers = attendanceUserService.queryByUsersAndGroupFilterSecondment(date, date, null, selfAndChildrenGroupIds);
List<String> userIds = attendanceGroupUsers.stream().map(AttendanceGroupUser::getUserId).collect(Collectors.toList());
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
List<String> userIdsForFilterStatus = getUserIdsForFilterStatus(userIds, UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE, UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_RULE_CHANGE_REMINDER);
return userIdsForFilterStatus;
}
/**
* 根据配置多个code来过滤出开关都开启的用户集合
*
* @param userIds
* @param settingCodes
* @return
*/
public List<String> getUserIdsForFilterStatus(List<String> userIds, UserSettingEnum... settingCodes) {
// 判断前置 开启考勤消息提醒 开启极速打卡成功提醒
List<String> userSettingList = new ArrayList<>();
Arrays.stream(settingCodes).forEach(v -> userSettingList.add(v.getCode()));
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
List<UserSettingVo> settingList = attendanceUserSettingService.getSettingList(userIds, UserSettingTypeEnum.USER.getCode(), userSettingList);
Map<String, List<UserSettingVo>> collect = settingList.stream().collect(Collectors.groupingBy(UserSettingVo::getAssociationId));
userSettingList.clear();
collect.forEach((userId, settings) -> {
if (settings.stream().allMatch(setting -> Objects.equals(setting.getStatus(), 1))) {
userSettingList.add(userId);
}
});
return userSettingList;
}
public boolean checkBeforeCondition(String userId, UserSettingEnum... settingCodes) {
// 判断前置 开启考勤消息提醒 开启极速打卡成功提醒
List<String> userSettingList = new ArrayList<>();
Arrays.stream(settingCodes).forEach(v -> userSettingList.add(v.getCode()));
if (StringUtil.isEmpty(userId)) {
return false;
}
List<UserSettingVo> settingList = attendanceUserSettingService.getSettingList(List.of(userId), UserSettingTypeEnum.USER.getCode(), userSettingList);
if (null == settingList || settingList.isEmpty()) {
return false;
}
Map<String, UserSettingVo> map = settingList.stream().collect(Collectors.toMap(UserSettingVo::getCode, Function.identity()));
boolean result = true;
for (String code : userSettingList) {
result = checkRule(code, map);
if (!result) {
break;
}
}
return result;
}
private boolean checkRule(String code, Map<String, UserSettingVo> map) {
switch (code) {
case UserSettingEnum.MESSAGE_RECEIVE:
case UserSettingEnum.SPEED_CHECK_SUCCESS_REMINDER:
case UserSettingEnum.MISSING_CHECKIN_REMINDER:
case UserSettingEnum.MISSING_END_WORK_REMINDER:
case UserSettingEnum.CLASS_ABSENCE_REMINDER:
case UserSettingEnum.DAILY_REPORT:
case UserSettingEnum.PERSONAL_MONTHLY_REPORT:
case UserSettingEnum.ATTENDANCE_GROUP_LOCK_UNLOCK_NOTICE:
case UserSettingEnum.CLASS_CHANGE_REMINDER:
case UserSettingEnum.PRE_WORK_REMINDER:
case UserSettingEnum.END_WORK_REMINDER:
case UserSettingEnum.ATTENDANCE_RESULT_CHANGE_REMINDER:
UserSettingVo absenceSetting = map.get(code);
if (null == absenceSetting) {
return false;
} else {
return absenceSetting.getStatus().equals(ConstantUtil.NUM_TRUE);
}
default:
return true;
}
}
}

View File

@@ -0,0 +1,87 @@
package jnpf.attendance.service.handle.notice;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.BeforeClockInModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.RemindClockInNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 打卡前提醒
*
* @author yanwenfu
* @create 2024-08-15
*/
@Service(value = AttendanceConstant.BEFORE_CLOCK_IN)
public class BeforeClockInNotice implements AttendanceNotice<BeforeClockInModel, RemindClockInNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(RemindClockInNoticeModel model) {
if (ConstantUtil.ON_WORK.equals(model.getClockInType())) {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_PRE_WORK_REMINDER);
} else {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_END_WORK_REMINDER);
}
}
@Override
public List<BeforeClockInModel> generatingData(RemindClockInNoticeModel model) {
BeforeClockInModel beforeClockInModel = BeforeClockInModel.builder()
.workTimeStr(null == model.getWorkTime() ? "--" : DateDetail.getDate2Str(model.getWorkTime(), DateDetail.DF9))
.remark(ConstantUtil.ON_WORK.equals(model.getClockInType()) ? AttendanceConstant.TITLE_BEFORE_ON_WORK : AttendanceConstant.TITLE_BEFORE_OFF_WORK)
.clockInType(model.getClockInType())
.build();
return List.of(beforeClockInModel);
}
@Override
public List<String> getRecipient(RemindClockInNoticeModel model) {
return List.of(model.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(RemindClockInNoticeModel model, String noticeId) {
List<JumpUrl> list = new ArrayList<>();
list.add(new JumpUrl(AttendanceConstant.BTN_RULE_URL + "?day=" + DateDetail.getDate2Str(new Date(), DateDetail.DF), AttendanceConstant.BTN_NAME_TO_DETAIL, AttendanceConstant.COLOR_BLACK));
list.add(new JumpUrl(AttendanceConstant.BTN_FAST_UPDATE_URL, AttendanceConstant.BTN_NAME_GO, AttendanceConstant.COLOR_BLUE));
return SystemNoticeStrategy.builder()
.title(ConstantUtil.ON_WORK.equals(model.getClockInType()) ? AttendanceConstant.TITLE_BEFORE_ON_WORK : AttendanceConstant.TITLE_BEFORE_OFF_WORK)
.noticeModuleEnum(NoticeModuleEnum.KQ_DK)
.jumpUrls(list)
.build();
}
@Override
public String getContext(List<BeforeClockInModel> dataList) {
if (null == dataList || dataList.isEmpty()) {
return "";
}
BeforeClockInModel model = dataList.get(0);
if (ConstantUtil.ON_WORK.equals(model.getClockInType())) {
return model.getWorkTimeStr() + " " + AttendanceConstant.TITLE_BEFORE_ON_WORK + "!";
} else {
return model.getWorkTimeStr() + " " + AttendanceConstant.TITLE_BEFORE_OFF_WORK + "!";
}
}
}

View File

@@ -0,0 +1,96 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.attendance.service.AttendanceSuperAdminService;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroup;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.model.attendance.model.*;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
import static jnpf.constants.AttendancePermissionConstant.MANAGER;
import static jnpf.constants.AttendancePermissionConstant.SCHEDULING;
@Component(AttendanceConstant.CONSEC_UNSCHEDULED)
@Slf4j
public class ConsecUnscheduledNotice implements AttendanceNotice<ConsecUnscheduledModel, ConsecUnscheduledNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Autowired
private AttendanceGroupService attendanceGroupService;
@Autowired
private AttendanceSuperAdminService attendanceSuperAdminService;
@Override
public Boolean isPass(ConsecUnscheduledNoticeModel attendanceNoticeModel) {
return Boolean.TRUE;
}
@Override
public List<ConsecUnscheduledModel> generatingData(ConsecUnscheduledNoticeModel attendanceNoticeModel) {
List<ConsecUnscheduledModel> shiftChangModels = CollUtil.newArrayList();
if (CollUtil.isEmpty(attendanceNoticeModel.getUserIds())) {
return shiftChangModels;
}
List<PartUserInfoVo> infoByIds = userAntifreeze.getInfoByIds(attendanceNoticeModel.getUserIds(), attendanceNoticeModel.getTenantId());
if (CollUtil.isEmpty(infoByIds)) {
return shiftChangModels;
}
List<String> collect = infoByIds.stream().map(PartUserInfoVo::getRealName).collect(Collectors.toList());
AttendanceGroup byId = attendanceGroupService.getById(attendanceNoticeModel.getGroupId());
if (Objects.isNull(byId)) {
return shiftChangModels;
}
attendanceNoticeModel.setAttendanceGroup(new AttendanceGroupParam(attendanceNoticeModel.getGroupId(),byId.getGroupName()));
shiftChangModels.add(new ConsecUnscheduledModel(byId.getGroupName(), collect));
return shiftChangModels;
}
@Override
public List<String> getRecipient(ConsecUnscheduledNoticeModel attendanceNoticeModel) {
Map<String, List<String>> stringListMap = attendanceSuperAdminService.queryPermissionBySpecify(CollUtil.newArrayList(attendanceNoticeModel.getGroupId()), List.of(SCHEDULING), List.of(MANAGER));
List<String> orDefault = stringListMap.getOrDefault("-1", CollUtil.newArrayList());
List<String> orDefault1 = stringListMap.getOrDefault(attendanceNoticeModel.getGroupId(), CollUtil.newArrayList());
orDefault.addAll(orDefault1);
return orDefault.stream().distinct().filter(Objects::nonNull).collect(Collectors.toList());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(ConsecUnscheduledNoticeModel attendanceNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(BTN_SCHEDULE_URL, JSON.toJSONString(attendanceNoticeModel.getAttendanceGroup()))).urlName(BTN_SCHEDULE_GO).color(COLOR_BLACK).build());
return SystemNoticeStrategy.builder()
.title(ATTENDANCE_NOTICE_CONSEC_UNSCHEDULED_TITLE)
.noticeModuleEnum(NoticeModuleEnum.KQ_PB)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<ConsecUnscheduledModel> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
StringBuffer stringBuffer = new StringBuffer();
ConsecUnscheduledModel shiftChangModel = data.stream().findFirst().orElse(null);
stringBuffer.append("考勤组:").append(shiftChangModel.getGroupName()).append("</br>");
List<String> userNames = shiftChangModel.getUserNames();
stringBuffer.append("相关成员:").append(StringUtil.join(userNames.stream().limit(3).collect(Collectors.toList()), "")).append(userNames.size() > 3 ? ("等共计" + userNames.size() + "名成员") : "");
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,71 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.*;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* 连续缺勤消息
*
* @author yanwenfu
* @create 2024-08-12
*/
@Service(value = AttendanceConstant.CONSECUTIVE_ABSENCE)
public class ConsecutiveAbsenceNotice implements AttendanceNotice<ConsecutiveAbsenceModel, ConsecutiveAbsenceNoticeModel> {
@Override
public Boolean isPass(ConsecutiveAbsenceNoticeModel model) {
return Boolean.TRUE;
}
@Override
public List<ConsecutiveAbsenceModel> generatingData(ConsecutiveAbsenceNoticeModel model) {
ConsecutiveAbsenceModel consecutiveAbsenceModel = ConsecutiveAbsenceModel.builder()
.groupName(model.getGroupName())
.userName(model.getUserName())
.absenceDate(model.getAbsenceDate())
.absenceDetailModel(model.getAbsenceDetailModel())
.build();
return List.of(consecutiveAbsenceModel);
}
@Override
public List<String> getRecipient(ConsecutiveAbsenceNoticeModel attendanceNoticeModel) {
return attendanceNoticeModel.getToUserList();
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(ConsecutiveAbsenceNoticeModel model, String noticeId) {
List<JumpUrl> list = new ArrayList<>();
list.add(new JumpUrl(String.format(AttendanceConstant.BTN_CONSECUTIVE_ABSENCE_URL, noticeId), AttendanceConstant.BTN_NAME_TO_DETAIL, AttendanceConstant.COLOR_BLACK));
list.add(new JumpUrl(String.format(AttendanceConstant.ADMINISTRATOR_CHANGE_URL2, model.getGroupId()), AttendanceConstant.ADMINISTRATOR_CHANGE_BUTTON_NAME2, AttendanceConstant.COLOR_BLUE));
return SystemNoticeStrategy.builder()
.title(AttendanceConstant.TITLE_CONSECUTIVE_ABSENCE)
.noticeModuleEnum(NoticeModuleEnum.KQ_DK)
.jumpUrls(list)
.build();
}
@Override
public String getContext(List<ConsecutiveAbsenceModel> dataList) {
if (null == dataList || dataList.isEmpty()) {
return "";
}
ConsecutiveAbsenceModel model = dataList.get(0);
return "考勤组:" + model.getGroupName() + "</br>" +
"成员:" + model.getUserName() + "</br>" +
"考勤时间:" + model.getAbsenceDate();
}
}

View File

@@ -0,0 +1,111 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.FastClockInNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.QuickClockInModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import jnpf.util.StringUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* 极速打卡消息
*
* @author yanwenfu
* @create 2024-08-12
*/
@Service(value = AttendanceConstant.FAST_CLOCK_IN)
public class FastClockInNotice implements AttendanceNotice<QuickClockInModel, FastClockInNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(FastClockInNoticeModel model) {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_SPEED_CHECK_SUCCESS_REMINDER);
}
@Override
public List<QuickClockInModel> generatingData(FastClockInNoticeModel model) {
QuickClockInModel quickClockInModel = QuickClockInModel.builder()
.workTimeStr(DateDetail.getDate2Str(model.getWorkTime(), DateDetail.DF9))
.remark(getTitle(model.getAttendanceNoticeEnum()))
.clockInTimeStr(DateDetail.getDate2Str(model.getClockIn().getClockInTime(), DateDetail.DF10))
.clockInMethod(getClockInMethod(model.getClockIn().getDeviceType()))
.clockInAddress(StringUtil.isEmpty(model.getClockIn().getAddress()) ? "--" : model.getClockIn().getAddress())
.build();
return List.of(quickClockInModel);
}
private String getClockInMethod(Integer deviceType) {
switch (deviceType) {
case ConstantUtil.DEVICE_PLACE:
return "GPS地点打卡";
case ConstantUtil.DEVICE_WIFI:
return "WIFI打卡";
case ConstantUtil.DEVICE_MACHINE:
return "考勤机打卡";
default:
return "未知";
}
}
@Override
public List<String> getRecipient(FastClockInNoticeModel attendanceNoticeModel) {
return CollUtil.newArrayList(attendanceNoticeModel.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(FastClockInNoticeModel model, String noticeId) {
List<JumpUrl> list = new ArrayList<>();
list.add(new JumpUrl(AttendanceConstant.BTN_FAST_DETAIL_URL, AttendanceConstant.BTN_NAME_TO_DETAIL, AttendanceConstant.COLOR_BLACK));
list.add(new JumpUrl(AttendanceConstant.BTN_FAST_UPDATE_URL, AttendanceConstant.BTN_NAME_FAST_UPDATE, AttendanceConstant.COLOR_BLUE));
return SystemNoticeStrategy.builder()
.title(getTitle(model.getAttendanceNoticeEnum()))
.noticeModuleEnum(NoticeModuleEnum.KQ_DK)
.jumpUrls(list)
.build();
}
private String getTitle(AttendanceNoticeEnum attendanceNoticeEnum) {
String title = "";
if (AttendanceNoticeEnum.CHECK_IN_QUICK.equals(attendanceNoticeEnum)) {
title = AttendanceConstant.ON_WORK;
}
if (AttendanceNoticeEnum.CHECK_OUT_QUICK.equals(attendanceNoticeEnum)) {
title = AttendanceConstant.OFF_WORK;
}
return String.format(AttendanceConstant.TITLE_FAST, title);
}
@Override
public String getContext(List<QuickClockInModel> dataList) {
if (null == dataList || dataList.isEmpty()) {
return "";
}
QuickClockInModel model = dataList.get(0);
return model.getWorkTimeStr() + model.getRemark()+ "!" + "</br>" +
"打卡时间:" + model.getClockInTimeStr() + "</br>" +
"考勤方式:" + model.getClockInMethod() + "</br>" +
"考勤点:" + model.getClockInAddress();
}
}

View File

@@ -0,0 +1,105 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.base.UserInfo;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.model.attendance.model.AdminUpdateModel;
import jnpf.model.attendance.model.AdminUpdateNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static jnpf.constants.AttendanceConstant.*;
import static jnpf.enums.attendance.UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE;
/**
* 考勤组锁定通知
*/
@Component(AttendanceConstant.ADMINISTRATOR_CHANGE)
public class GroupAdminUpdateNotice implements AttendanceNotice<AdminUpdateModel, AdminUpdateNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(AdminUpdateNoticeModel noticeModel) {
return Boolean.TRUE;
}
@Override
public List<AdminUpdateModel> generatingData(AdminUpdateNoticeModel noticeModel) {
return CollUtil.newArrayList(AdminUpdateModel.builder()
.type(noticeModel.getType())
.groupName(noticeModel.getGroupName())
.currentAuthority(noticeModel.getCurrentAuthority())
.sonAuthority(noticeModel.getSonAuthority())
.build());
}
@Override
public List<String> getRecipient(AdminUpdateNoticeModel noticeModel) {
return attendanceNoticeHandler.getUserIdsForFilterStatus(noticeModel.getUserIds(), ATTENDANCE_SETTING_MESSAGE_RECEIVE);
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(AdminUpdateNoticeModel noticeModel, String noticeId) {
UserInfo user = UserProvider.getUser();
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
if (noticeModel.getType().equals(1)) {
objects.add(JumpUrl.builder().url(String.format(ADMINISTRATOR_CHANGE_URL1, noticeId))
.urlName(ADMINISTRATOR_CHANGE_BUTTON_NAME1).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(String.format(ADMINISTRATOR_CHANGE_URL2, noticeModel.getGroupId()))
.urlName(ADMINISTRATOR_CHANGE_BUTTON_NAME2).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(String.format(ADMINISTRATOR_CHANGE_TITLE1, noticeModel.getGroupName()))
.noticeModuleEnum(NoticeModuleEnum.KQZ_GLY_BD)
.jumpUrls(objects)
.build();
} else {
objects.add(new JumpUrl(String.format(AttendanceConstant.GROUP_LOCK_URL1, user.getUserId()), AttendanceConstant.GROUP_LOCK_BUTTON_NAME1, AttendanceConstant.COLOR_BLACK,3,"contactInfo", JSON.toJSONString(new JSONObject(){{
put("contactId", user.getUserId());
}})));
return SystemNoticeStrategy.builder()
.title(String.format(ADMINISTRATOR_CHANGE_TITLE2, noticeModel.getGroupName()))
.noticeModuleEnum(NoticeModuleEnum.KQZ_GLY_BD)
.jumpUrls(objects)
.build();
}
}
@Override
public String getContext(List<AdminUpdateModel> data) {
StringBuffer stringBuffer = new StringBuffer();
AdminUpdateModel lockModel = data.stream().findFirst().orElse(null);
if (lockModel.getType().equals(1)) {
stringBuffer.append("当前考勤组权限:").append(lockModel.getCurrentAuthority());
} else {
UserInfo user = UserProvider.getUser();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(user.getUserId()), user.getTenantId());
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("操作人:无</br>");
} else {
stringBuffer.append("操作人:").append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")</br>");
}
stringBuffer.append("您已不能再对【").append(lockModel.getGroupName()).append("】进行相应操作(包含查看成员考勤信息,对考勤组规则进行配置,对成员进行排班等操作)。").append("</br>");
}
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,107 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroupUser;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.AttendanceNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.LockModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* 考勤组锁定通知
*/
@Component(AttendanceConstant.GROUP_LOCK)
public class GroupLockNotice implements AttendanceNotice<LockModel, AttendanceNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Resource
private AttendanceUserService attendanceUserService;
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(AttendanceNoticeModel noticeModel) {
return Boolean.TRUE;
}
@Override
public List<LockModel> generatingData(AttendanceNoticeModel noticeModel) {
List<LockModel> data = new ArrayList<>();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(noticeModel.getUserId()), noticeModel.getTenantId());
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
StringBuffer stringBuffer = new StringBuffer();
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("");
} else {
stringBuffer.append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")");
}
data.add(LockModel.builder()
.date(new Date())
.userName(stringBuffer.toString())
.build());
return data;
}
@Override
public List<String> getRecipient(AttendanceNoticeModel noticeModel) {
Date date = new Date();
List<AttendanceGroupUser> userList = attendanceUserService.getAttendanceGroupUsersOfSecondment(date, date, null, List.of(noticeModel.getGroupId()));
return CollUtil.isEmpty(userList) ? null : attendanceNoticeHandler.getUserIdsForFilterStatus(
userList.stream().map(AttendanceGroupUser::getUserId).distinct().collect(Collectors.toList()),
UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_LOCK_UNLOCK_NOTICE);
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(AttendanceNoticeModel noticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(GROUP_LOCK_URL1, noticeModel.getUserId()))
.urlName(GROUP_LOCK_BUTTON_NAME1).color(COLOR_BLACK)
.type(3)
.page("contactInfo")
.param(JSON.toJSONString(new JSONObject(){{
put("contactId", noticeModel.getUserId());
}}))
.build());
objects.add(JumpUrl.builder().url(String.format(GROUP_LOCK_URL2, noticeId))
.urlName(GROUP_LOCK_BUTTON_NAME2).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(TITLE_GROUP_LOCK)
.noticeModuleEnum(NoticeModuleEnum.KQZ_SD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<LockModel> data) {
StringBuffer stringBuffer = new StringBuffer();
LockModel lockModel = data.stream().findFirst().orElse(null);
stringBuffer.append("操作人:").append(lockModel.getUserName()).append("</br>");
stringBuffer.append("当前所在考勤组已被管理员锁定,无法再对").append(DateUtil.format(lockModel.getDate(), "yyyy年MM月dd日"))
.append("之前的出勤结果做变更!");
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,94 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroupUser;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.AttendanceNoticeModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.model.UnLockModel;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* 考勤组解锁通知
*/
@Component(AttendanceConstant.GROUP_UNLOCK)
public class GroupUnLockNotice implements AttendanceNotice<UnLockModel, AttendanceNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Resource
private AttendanceUserService attendanceUserService;
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(AttendanceNoticeModel noticeModel) {
return Boolean.TRUE;
}
@Override
public List<UnLockModel> generatingData(AttendanceNoticeModel noticeModel) {
List<UnLockModel> data = new ArrayList<>();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(noticeModel.getUserId()), noticeModel.getTenantId());
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
StringBuffer stringBuffer = new StringBuffer();
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("");
} else {
stringBuffer.append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")");
}
data.add(UnLockModel.builder()
.userName(stringBuffer.toString())
.build());
return data;
}
@Override
public List<String> getRecipient(AttendanceNoticeModel noticeModel) {
Date date = new Date();
List<AttendanceGroupUser> userList = attendanceUserService.getAttendanceGroupUsersOfSecondment(date, date, null, List.of(noticeModel.getGroupId()));
return CollUtil.isEmpty(userList) ? null : attendanceNoticeHandler.getUserIdsForFilterStatus(
userList.stream().map(AttendanceGroupUser::getUserId).distinct().collect(Collectors.toList()),
UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_ATTENDANCE_GROUP_LOCK_UNLOCK_NOTICE);
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(AttendanceNoticeModel noticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(GROUP_UNLOCK_URL, noticeId))
.urlName(GROUP_LOCK_BUTTON_NAME2).color(COLOR_BLACK).build());
return SystemNoticeStrategy.builder()
.title(TITLE_GROUP_UNLOCK)
.noticeModuleEnum(NoticeModuleEnum.KQZ_SD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<UnLockModel> data) {
StringBuffer stringBuffer = new StringBuffer();
UnLockModel unLockModel = data.stream().findFirst().orElse(null);
stringBuffer.append("操作人:").append(unLockModel.getUserName()).append("</br>");
stringBuffer.append("考勤组解锁后可以进行如下操作:");
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,63 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.dto.LineDrawingPeriodDto;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.LineShiftChangeNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
@Component(AttendanceConstant.LINE_SHIFT_NOT_SCHEDUING)
@Slf4j
public class LineNotSchedulingAttendanceNotice implements AttendanceNotice<LineDrawingPeriodDto, LineShiftChangeNoticeModel> {
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(LineShiftChangeNoticeModel attendanceNoticeModel) {
return true;
}
@Override
public List<LineDrawingPeriodDto> generatingData(LineShiftChangeNoticeModel attendanceNoticeModel) {
//查询时段数据
return attendanceNoticeModel.getPeriods();
}
@Override
public List<String> getRecipient(LineShiftChangeNoticeModel attendanceNoticeModel) {
return attendanceNoticeModel.getUserIds().stream().filter(userId -> attendanceNoticeHandler.checkBeforeCondition(userId, UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE)).collect(Collectors.toList());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(LineShiftChangeNoticeModel attendanceNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(BTN_LINE_SCHEDULE_URL, JSON.toJSONString(attendanceNoticeModel.getAttendanceGroup())) + "&moduleId=" + attendanceNoticeModel.getModuleId()).urlName(BTN_SCHEDULE_GO).color(COLOR_BLACK).build());
return SystemNoticeStrategy.builder()
.title(ATTENDANCE_NOTICE_LINE_SCHEDULED_TITLE)
.noticeModuleEnum(NoticeModuleEnum.BC_BD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<LineDrawingPeriodDto> data) {
return "提醒通知:请您及时为划线排班人员排班!如已排班,请忽略";
}
}

View File

@@ -0,0 +1,82 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.dto.LineDrawingPeriodDto;
import jnpf.model.attendance.model.*;
import jnpf.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
@Component(AttendanceConstant.LINE_SHIFT_CHANG)
@Slf4j
public class LineShiftChangAttendanceNotice implements AttendanceNotice<LineDrawingPeriodDto, LineShiftChangeNoticeModel> {
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(LineShiftChangeNoticeModel attendanceNoticeModel) {
return true;
}
@Override
public List<LineDrawingPeriodDto> generatingData(LineShiftChangeNoticeModel attendanceNoticeModel) {
//查询时段数据
if (CollUtil.isEmpty(attendanceNoticeModel.getPeriods())) {
return List.of(LineDrawingPeriodDto.builder().day(attendanceNoticeModel.getDay()).build());
}
return attendanceNoticeModel.getPeriods();
}
@Override
public List<String> getRecipient(LineShiftChangeNoticeModel attendanceNoticeModel) {
return CollUtil.isEmpty(attendanceNoticeModel.getUserIds()) ? List.of() : attendanceNoticeModel.getUserIds().stream().filter(userId -> attendanceNoticeHandler.checkBeforeCondition(userId, UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE)).collect(Collectors.toList());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(LineShiftChangeNoticeModel attendanceNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
boolean hasSchedule = attendanceNoticeModel.getPeriods().stream().anyMatch(vo -> StringUtil.isNotEmpty(vo.getStart()));
if (hasSchedule) {
objects.add(JumpUrl.builder().url(BTN_FAST_UPDATE_URL).urlName(BTN_NAME_GO).color(COLOR_BLACK).build());
} else {
objects.add(JumpUrl.builder().build());
}
return SystemNoticeStrategy.builder()
.title(ATTENDANCE_NOTICE_LINE_SHIFT_CHANGE_TITLE)
.noticeModuleEnum(NoticeModuleEnum.BC_BD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<LineDrawingPeriodDto> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
StringBuilder stringBuffer = new StringBuilder();
String dayStr = data.stream().map(LineDrawingPeriodDto::getDay).distinct().map(day -> DateUtil.format(day, "yyyy年MM月dd日") + "(" + DateUtil.dayOfWeekEnum(day).toChinese() + ")").collect(Collectors.joining(""));
stringBuffer.append("提醒通知:您在").append(dayStr);
if (data.stream().allMatch(vo -> Objects.isNull(vo.getStart()))) {
stringBuffer.append("暂无排班。");
return stringBuffer.toString();
}
if (data.stream().allMatch(vo -> StringUtil.isEmpty(vo.getStart()))) {
stringBuffer.append("的排班已取消。");
return stringBuffer.toString();
}
List<LineDrawingPeriodDto> data1 = data.stream().collect(Collectors.groupingBy(LineDrawingPeriodDto::getDay)).values().stream().findFirst().orElse(List.of());
stringBuffer.append("的排班调整为:").append(data1.stream().sorted(Comparator.comparing(LineDrawingPeriodDto::getStartType).thenComparing(LineDrawingPeriodDto::getStart)).map(vo -> vo.getStart() + "~" + vo.getEnd()).collect(Collectors.joining(""))).append("");
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,134 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import jnpf.constants.AttendanceConstant;
import jnpf.engine.DataStatisticsApi;
import jnpf.engine.model.flowstatistics.vo.TemplatePagesVo;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.NoClockInModel;
import jnpf.model.attendance.model.NoClockInNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.util.ConstantUtil;
import jnpf.util.DateDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 缺卡/旷工消息服务
*
* @author yanwenfu
* @create 2024-08-13
*/
@Service(value = AttendanceConstant.WORK_MISSING)
public class NoClockInNotice implements AttendanceNotice<NoClockInModel, NoClockInNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Autowired
private DataStatisticsApi dataStatisticsApi;
@Override
public Boolean isPass(NoClockInNoticeModel model) {
// 上班缺卡 下班缺卡 旷工
if (ConstantUtil.NUM_TRUE == model.getAbsence()) {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_CLASS_ABSENCE_REMINDER);
} else if (ConstantUtil.ON_WORK.equals(model.getClockInType())) {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_MISSING_CHECKIN_REMINDER);
} else {
return attendanceNoticeHandler.checkBeforeCondition(model.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_MISSING_END_WORK_REMINDER);
}
}
@Override
public List<NoClockInModel> generatingData(NoClockInNoticeModel model) {
String workTimeStr;
if (ConstantUtil.NUM_TRUE == model.getAbsence()) {
workTimeStr = DateDetail.getDate2Str(model.getOnWorkTime(), DateDetail.DF9)+ "" + DateDetail.getDate2Str(model.getOffWorkTime(), DateDetail.DF10);
} else if (ConstantUtil.ON_WORK.equals(model.getClockInType())) {
workTimeStr = DateDetail.getDate2Str(model.getOnWorkTime(), DateDetail.DF9);
} else {
workTimeStr = DateDetail.getDate2Str(model.getOffWorkTime(), DateDetail.DF9);
}
NoClockInModel noClockInModel = NoClockInModel.builder()
.workTimeStr(workTimeStr)
.remark(getTitle(model.getAbsence(), model.getClockInType()))
.absence(model.getAbsence())
.clockInType(model.getClockInType())
.build();
return List.of(noClockInModel);
}
private String getTitle(Integer absence, Integer clockInType) {
if (ConstantUtil.NUM_TRUE == absence) {
return AttendanceConstant.TITLE_ABSENCE;
} else if (ConstantUtil.ON_WORK.equals(clockInType)) {
return AttendanceConstant.TITLE_ON_WORK;
} else {
return AttendanceConstant.TITLE_OFF_WORK;
}
}
@Override
public List<String> getRecipient(NoClockInNoticeModel model) {
return List.of(model.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(NoClockInNoticeModel model, String noticeId) {
// 查询url需要的参数(补卡审批)
List<TemplatePagesVo> list = dataStatisticsApi.getFeignTemplatePagesByBusinessType(ConstantUtil.REPAIR_TYPE);
String url = "";
if (null != list && !list.isEmpty()) {
TemplatePagesVo template = list.get(0);
JSONObject json = new JSONObject();
// 前端需要回显补卡的记录 所需的json格式
JSONObject data = new JSONObject();
data.set("clockInResultId", model.getClockInResultId());
json.set("interfaceData", data);
json.set("extraData", new JSONObject());
json.set("paramsData", new JSONObject());
JSONObject sourceData = new JSONObject();
sourceData.set("text", model.getClockInType().equals(ConstantUtil.ON_WORK) ? DateDetail.getDateTime2Str(model.getOnWorkTime()) : DateDetail.getDateTime2Str(model.getOffWorkTime()));
json.set("sourceData", sourceData);
json.set("tableData", new JSONArray());
url = String.format(AttendanceConstant.BTN_REPAIR_URL, template.getFlowId(), template.getTemplateId(), json);
}
return SystemNoticeStrategy.builder()
.title(getTitle(model.getAbsence(), model.getClockInType()))
.noticeModuleEnum(NoticeModuleEnum.KQ_DK)
.jumpUrls(List.of(new JumpUrl(url, AttendanceConstant.BTN_NAME_REPAIR, AttendanceConstant.COLOR_BLACK, "__UNI__65CF373")))
.build();
}
@Override
public String getContext(List<NoClockInModel> dataList) {
if (null == dataList || dataList.isEmpty()) {
return "";
}
NoClockInModel model = dataList.get(0);
if (ConstantUtil.NUM_TRUE == model.getAbsence()) {
return model.getWorkTimeStr() + " 上下班均未打卡,计为旷工!";
} else if (ConstantUtil.ON_WORK.equals(model.getClockInType())) {
return model.getWorkTimeStr() + " 上班已缺卡!";
} else {
return model.getWorkTimeStr() + " 下班已缺卡!";
}
}
}

View File

@@ -0,0 +1,132 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.mapper.AttendanceManagerPermissionMapper;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.base.UserInfo;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.AttendanceGroupUser;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.RuleChangeModel;
import jnpf.model.attendance.model.RuleChangeNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.vo.AttendanceGroupAdminVo;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.ATTENDANCE_NOTICE_ADMIN_RULE_CHANGE_TITLE;
import static jnpf.constants.AttendanceConstant.ATTENDANCE_NOTICE_RULE_CHANGE_TITLE;
@Component(AttendanceConstant.RULE_CHANGE_RATIO)
public class RuleChangeAttendanceNotice implements AttendanceNotice<RuleChangeModel, RuleChangeNoticeModel> {
@Autowired
private AttendanceGroupService attendanceGroupService;
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Autowired
private UserAntifreeze userAntifreeze;
@Override
public Boolean isPass(RuleChangeNoticeModel attendanceNoticeModel) {
return Boolean.TRUE;
}
@Override
public List<RuleChangeModel> generatingData(RuleChangeNoticeModel attendanceNoticeModel) {
String tips = "";
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_RATIO)) {
tips = String.format("出勤换算比由%s小时/天改为%s小时/天", attendanceNoticeModel.getOldValue(), attendanceNoticeModel.getNewValue());
}
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_FIELD)) {
tips = String.format("外勤打卡已调整为%s外勤打卡", Objects.equals(attendanceNoticeModel.getNewValue(), 1) ? "允许" : "不允许");
}
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_CARD_MAKEUP)) {
tips = String.format("补卡规则已调整为%s补卡", Objects.equals(attendanceNoticeModel.getNewValue(), 1) ? "允许" : "不允许");
}
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_GPS_SWIFT)) {
tips = String.format("考勤方式已%s使用GPS地点打卡", Objects.equals(attendanceNoticeModel.getNewValue(), 1) ? "允许" : "禁止");
if (Objects.equals(attendanceNoticeModel.getNewValue(), 1)) {
StringBuilder sb = new StringBuilder("</br><span style='font-weight: bold;'>可使用考勤点:</span>").append("</br>");
if (CollUtil.isNotEmpty(attendanceNoticeModel.getAddressList())) {
sb.append(String.join("</br>", attendanceNoticeModel.getAddressList()));
}
tips += sb.toString();
}
}
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_WIFI_SWIFT)) {
tips = String.format("考勤方式已%s使用WIFI打卡", Objects.equals(attendanceNoticeModel.getNewValue(), 1) ? "允许" : "不允许");
if (Objects.equals(attendanceNoticeModel.getNewValue(), 1)) {
StringBuilder sb = new StringBuilder("</br><span style='font-weight: bold;'>可使用考勤点:</span>").append("</br>");
if (CollUtil.isNotEmpty(attendanceNoticeModel.getAddressList())) {
sb.append(String.join("", attendanceNoticeModel.getAddressList()));
}
tips += sb.toString();
}
}
if (Objects.equals(attendanceNoticeModel.getAttendanceNoticeEnum(), AttendanceNoticeEnum.RULE_CHANGE_KQJ_SWIFT)) {
tips = String.format("考勤方式已%s使用考勤机打卡", Objects.equals(attendanceNoticeModel.getNewValue(), 1) ? "允许" : "不允许");
if (Objects.equals(attendanceNoticeModel.getNewValue(), 1)) {
StringBuilder sb = new StringBuilder("</br><span style='font-weight: bold;'>可使用考勤点:</span>").append("</br>");
if (CollUtil.isNotEmpty(attendanceNoticeModel.getAddressList())) {
sb.append(String.join("", attendanceNoticeModel.getAddressList()));
}
tips += sb.toString();
}
}
AttendanceGroup byId = attendanceGroupService.getById(attendanceNoticeModel.getGroupId());
return CollUtil.newArrayList(RuleChangeModel.builder()
.groupName(byId.getGroupName())
.tips(tips)
.build());
}
@Override
public List<String> getRecipient(RuleChangeNoticeModel attendanceNoticeModel) {
return attendanceNoticeHandler.getRecipientForSelfAndChild(attendanceNoticeModel.getGroupId(), attendanceNoticeModel.getIsAdmin());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(RuleChangeNoticeModel attendanceNoticeModel, String noticeId) {
return SystemNoticeStrategy.builder()
.noticeModuleEnum(NoticeModuleEnum.KQZ_BD)
.title(attendanceNoticeModel.getIsAdmin() ? ATTENDANCE_NOTICE_ADMIN_RULE_CHANGE_TITLE : ATTENDANCE_NOTICE_RULE_CHANGE_TITLE)
.isConfirm(Boolean.TRUE)
.build();
}
@Override
public String getContext(List<RuleChangeModel> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
UserInfo user = UserProvider.getUser();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(user.getUserId()), user.getTenantId());
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
StringBuffer stringBuffer = new StringBuffer();
RuleChangeModel ruleChangeModel = data.stream().findFirst().orElse(null);
stringBuffer.append("考勤组:").append(ruleChangeModel.getGroupName()).append("</br>");
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("操作人:无</br>");
} else {
stringBuffer.append("操作人:").append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")</br>");
}
stringBuffer.append(ruleChangeModel.getTips());
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,96 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.DaySettlementModel;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SettlementNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.util.DateUtil;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* 日统计考勤结算通知
*/
@Component(AttendanceConstant.INDIVIDUAL_DAILY_STATISTICS)
public class SettlementDayNotice implements AttendanceNotice<DaySettlementModel, SettlementNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(SettlementNoticeModel settlementNoticeModel) {
return attendanceNoticeHandler.checkBeforeCondition(settlementNoticeModel.getUserId(),
UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_DAILY_REPORT);
}
@Override
public List<DaySettlementModel> generatingData(SettlementNoticeModel settlementNoticeModel) {
return settlementNoticeModel.getDayNoticeModelList().stream().map(item -> DaySettlementModel.builder()
.groupName(item.getGroupName())
.shiftStr(String.join(" ", item.getShiftList()))
.shiftTimeStr(String.join(" ", item.getShiftTimeList()))
.clockTimeStr(String.join("|", item.getClockTimeList()))
.clockTime(item.getClockTime())
.shouldAttendHours(item.getShouldAttendHours())
.actualAttendHours(item.getActualAttendHours())
.workingHours(item.getWorkingHours())
.lateTimes(item.getLateTimes())
.lateMinutes(item.getLateMinutes())
.earlyLeaveTimes(item.getEarlyLeaveTimes())
.earlyLeaveMinutes(item.getEarlyLeaveMinutes())
.absenceCardTimes(item.getAbsenceCardTimes())
.absenceCardHours(item.getAbsenceCardHours())
.absenceTimes(item.getAbsenceTimes())
.absenceHours(item.getAbsenceHours())
.leaveHours(item.getLeaveHours())
.leaveDays(item.getLeaveDays())
.busDays(item.getBusDays())
.outDays(item.getOutDays())
.outHours(item.getOutHours())
.overtimeHours(item.getOvertimeHours())
.endDate(DateUtil.dateToString(new Date(), "yyyy年MM月dd日HH:mm"))
.build()).collect(Collectors.toList());
}
@Override
public List<String> getRecipient(SettlementNoticeModel settlementNoticeModel) {
return CollUtil.newArrayList(settlementNoticeModel.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(SettlementNoticeModel settlementNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(INDIVIDUAL_DAILY_STATISTICS_URL1, noticeId))
.urlName(INDIVIDUAL_DAILY_STATISTICS_BUTTON_NAME1).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(INDIVIDUAL_DAILY_STATISTICS_URL2)
.urlName(INDIVIDUAL_DAILY_STATISTICS_BUTTON_NAME2).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(settlementNoticeModel.getTitle())
.noticeModuleEnum(NoticeModuleEnum.GR_RB)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<DaySettlementModel> data) {
DaySettlementModel daySettlementModel = data.stream().findFirst().orElse(null);
return "考勤组" + daySettlementModel.getGroupName() + "</br>" +
"当日班次:" + daySettlementModel.getShiftStr() + "</br>" +
"班次时间:" + daySettlementModel.getShiftTimeStr() + "</br>" +
"打卡时间:" + daySettlementModel.getClockTimeStr() + "</br>";
}
}

View File

@@ -0,0 +1,129 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.MonthSettlementModel;
import jnpf.model.attendance.model.SettlementNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* 日统计考勤结算通知
*/
@Component(AttendanceConstant.INDIVIDUAL_MONTHLY_STATISTICS)
public class SettlementMonthNotice implements AttendanceNotice<MonthSettlementModel, SettlementNoticeModel> {
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(SettlementNoticeModel settlementNoticeModel) {
return attendanceNoticeHandler.checkBeforeCondition(settlementNoticeModel.getUserId(),
UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_PERSONAL_MONTHLY_REPORT);
}
@Override
public List<MonthSettlementModel> generatingData(SettlementNoticeModel settlementNoticeModel) {
return settlementNoticeModel.getMonthNoticeModelList().stream().map(item -> MonthSettlementModel.builder()
.cycleDate(item.getCycleDate())
.groupName(item.getGroupName())
.effectiveAttendDays(item.getEffectiveAttendDays())
.leaveDays(item.getLeaveDays())
.leaveHours(item.getLeaveHours())
.lateTimes(item.getLateTimes())
.earlyLeaveTimes(item.getEarlyLeaveTimes())
.absenceCardTimes(item.getAbsenceCardTimes())
.absenceTimes(item.getAbsenceTimes())
.busTimes(item.getBusTimes())
.outTimes(item.getOutTimes())
.overtimeTimes(item.getOvertimeTimes())
.endDate(item.getEndDate())
.build()).collect(Collectors.toList());
}
@Override
public List<String> getRecipient(SettlementNoticeModel settlementNoticeModel) {
return CollUtil.newArrayList(settlementNoticeModel.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(SettlementNoticeModel settlementNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(INDIVIDUAL_MONTHLY_STATISTICS_URL1, noticeId))
.urlName(INDIVIDUAL_MONTHLY_STATISTICS_BUTTON_NAME1).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(INDIVIDUAL_MONTHLY_STATISTICS_URL2)
.urlName(INDIVIDUAL_MONTHLY_STATISTICS_BUTTON_NAME2).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(settlementNoticeModel.getTitle())
.noticeModuleEnum(NoticeModuleEnum.GR_RB)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<MonthSettlementModel> data) {
MonthSettlementModel monthSettlementModel = data.stream().findFirst().orElse(null);
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append("时间:").append(monthSettlementModel.getCycleDate()).append("</br>");
stringBuffer.append("考勤组:").append(monthSettlementModel.getGroupName()).append("</br>");
stringBuffer.append("出勤情况:").append("</br>");
getTipsStr(monthSettlementModel, stringBuffer);
return stringBuffer.toString();
}
private void getTipsStr(MonthSettlementModel monthSettlementModel, StringBuilder tips) {
if (monthSettlementModel.getEffectiveAttendDays().compareTo(BigDecimal.ZERO) > 0) {
tips.append("出勤天数:").append(monthSettlementModel.getEffectiveAttendDays()).append("天</br>");
} else if (monthSettlementModel.getLeaveDays().compareTo(BigDecimal.ZERO) > 0) {
tips.append("请假天数:").append(getFieldValue(monthSettlementModel.getLeaveDays(), monthSettlementModel.getLeaveHours())).append("</br>");
} else if (monthSettlementModel.getLateTimes() > 0) {
tips.append("迟到次数:").append(monthSettlementModel.getLateTimes()).append("次</br>");
} else if (monthSettlementModel.getEarlyLeaveTimes() > 0) {
tips.append("早退次数:").append(monthSettlementModel.getEarlyLeaveTimes()).append("次</br>");
} else if (monthSettlementModel.getAbsenceCardTimes() > 0) {
tips.append("缺卡次数:").append(monthSettlementModel.getAbsenceCardTimes()).append("次</br>");
} else if (monthSettlementModel.getAbsenceTimes() > 0) {
tips.append("缺勤次数:").append(monthSettlementModel.getAbsenceTimes()).append("次</br>");
} else if (monthSettlementModel.getBusTimes() > 0) {
tips.append("出差次数:").append(monthSettlementModel.getBusTimes()).append("次</br>");
} else if (monthSettlementModel.getOutTimes() > 0) {
tips.append("外出次数:").append(monthSettlementModel.getOutTimes()).append("次</br>");
} else if (monthSettlementModel.getOvertimeTimes() > 0) {
tips.append("加班次数:").append(monthSettlementModel.getOvertimeTimes()).append("次</br>");
}
}
/**
* 生成组合字段值
*
* @param durationDays 时长天数
* @param durationHours 时长小时
* @return 组合字段值
*/
private static String getFieldValue(BigDecimal durationDays, BigDecimal durationHours) {
StringBuilder sb = new StringBuilder();
if (durationDays.compareTo(BigDecimal.ZERO) == 0 && durationHours.compareTo(BigDecimal.ZERO) == 0) {
sb.append("0天");
} else if (durationDays.compareTo(BigDecimal.ZERO) > 0 && durationHours.compareTo(BigDecimal.ZERO) > 0) {
sb.append(durationDays).append("").append(durationHours).append("小时");
} else if (durationDays.compareTo(BigDecimal.ZERO) == 0 && durationHours.compareTo(BigDecimal.ZERO) > 0) {
sb.append(durationHours).append("小时");
} else if (durationDays.compareTo(BigDecimal.ZERO) > 0 && durationHours.compareTo(BigDecimal.ZERO) == 0) {
sb.append(durationDays).append("");
}
return sb.toString();
}
}

View File

@@ -0,0 +1,118 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Maps;
import jnpf.constants.AttendanceConstant;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SettlementNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.model.TeamMonthSettlementModel;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
/**
* 日统计考勤结算通知
*/
@Component(AttendanceConstant.TEAM_MONTHLY_STATISTICS)
public class SettlementTeamMonthNotice implements AttendanceNotice<TeamMonthSettlementModel, SettlementNoticeModel> {
@Override
public Boolean isPass(SettlementNoticeModel settlementNoticeModel) {
return Boolean.TRUE;
}
@Override
public List<TeamMonthSettlementModel> generatingData(SettlementNoticeModel settlementNoticeModel) {
return settlementNoticeModel.getTeamMonthNoticeModelList().stream().map(item -> TeamMonthSettlementModel.builder()
.groupName(item.getGroupName())
.normalCount(item.getNormalCount())
.leaveCount(item.getLeaveCount())
.lateCount(item.getLateCount())
.earlyLeaveCount(item.getEarlyLeaveCount())
.absenceCardCount(item.getAbsenceCardCount())
.absenceCount(item.getAbsenceCount())
.busCount(item.getBusCount())
.outCount(item.getOutCount())
.overtimeCount(item.getOvertimeCount())
.endDate(item.getEndDate())
.build()).collect(Collectors.toList());
}
@Override
public List<String> getRecipient(SettlementNoticeModel settlementNoticeModel) {
return CollUtil.newArrayList(settlementNoticeModel.getUserIds());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(SettlementNoticeModel settlementNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(TEAM_MONTHLY_STATISTICS_URL1, noticeId))
.urlName(TEAM_MONTHLY_STATISTICS_BUTTON_NAME1).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(TEAM_MONTHLY_STATISTICS_URL2)
.urlName(TEAM_MONTHLY_STATISTICS_BUTTON_NAME2).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(settlementNoticeModel.getTitle())
.noticeModuleEnum(NoticeModuleEnum.GR_RB)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<TeamMonthSettlementModel> data) {
TeamMonthSettlementModel teamMonthSettlementModel = data.stream().findFirst().orElse(null);
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append("考勤组:").append(teamMonthSettlementModel.getGroupName()).append("</br>");
stringBuffer.append("出勤情况:").append("</br>");;
getTipsList(teamMonthSettlementModel, stringBuffer);
return stringBuffer.toString();
}
private void getTipsList(TeamMonthSettlementModel teamMonthSettlementModel, StringBuilder tips) {
LinkedHashMap<String, Integer> map = Maps.newLinkedHashMap();
if (teamMonthSettlementModel.getNormalCount() > 0) {
map.put("正常", teamMonthSettlementModel.getNormalCount());
}
if (teamMonthSettlementModel.getLeaveCount() > 0) {
map.put("请假", teamMonthSettlementModel.getLeaveCount());
}
if (teamMonthSettlementModel.getLateCount() > 0) {
map.put("迟到", teamMonthSettlementModel.getLateCount());
}
if (teamMonthSettlementModel.getEarlyLeaveCount() > 0) {
map.put("早退", teamMonthSettlementModel.getEarlyLeaveCount());
}
if (teamMonthSettlementModel.getAbsenceCardCount() > 0) {
map.put("缺卡", teamMonthSettlementModel.getAbsenceCardCount());
}
if (teamMonthSettlementModel.getAbsenceCount() > 0) {
map.put("旷工", teamMonthSettlementModel.getAbsenceCount());
}
if (teamMonthSettlementModel.getBusCount() > 0) {
map.put("出差", teamMonthSettlementModel.getBusCount());
}
if (teamMonthSettlementModel.getOutCount() > 0) {
map.put("外出", teamMonthSettlementModel.getOutCount());
}
if (teamMonthSettlementModel.getOvertimeCount() > 0) {
map.put("加班", teamMonthSettlementModel.getOvertimeCount());
}
int i = 0;
for (Map.Entry<String, Integer> stringIntegerEntry : map.entrySet()) {
if (i > 1) {
break;
}
tips.append(stringIntegerEntry.getKey()).append("").append(stringIntegerEntry.getValue()).append("人</br>");
i++;
}
}
}

View File

@@ -0,0 +1,173 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceShiftNameSettingService;
import jnpf.attendance.service.AttendanceShiftSettingPeriodService;
import jnpf.base.UserInfo;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.AttendanceShiftNameEntity;
import jnpf.entity.attendance.AttendanceShiftSettingPeriodEntity;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.ShiftChangModel;
import jnpf.model.attendance.model.ShiftChangeNoticeModel;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.vo.AttendanceShiftSettingPeriodVo;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
@Component(AttendanceConstant.SHIFT_CHANG)
@Slf4j
public class ShiftChangAttendanceNotice implements AttendanceNotice<ShiftChangModel, ShiftChangeNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Autowired
private AttendanceShiftNameSettingService attendanceShiftNameSettingService;
@Autowired
private AttendanceShiftSettingPeriodService attendanceShiftSettingPeriodService;
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(ShiftChangeNoticeModel attendanceNoticeModel) {
return attendanceNoticeHandler.checkBeforeCondition(attendanceNoticeModel.getUserId(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE,
UserSettingEnum.ATTENDANCE_SETTING_CLASS_CHANGE_REMINDER);
}
@Override
public List<ShiftChangModel> generatingData(ShiftChangeNoticeModel attendanceNoticeModel) {
List<ShiftChangModel> shiftChangModels = CollUtil.newArrayList();
//查询时段数据
List<DailyRuleResultVo> dailyRuleResultVos = attendanceNoticeModel.getDailyRuleResultVos();
List<String> collect = dailyRuleResultVos.stream().map(DailyRuleResultVo::getFromShiftId).filter(StringUtil::isNotEmpty).collect(Collectors.toList());
List<String> collect1 = dailyRuleResultVos.stream().map(DailyRuleResultVo::getToShiftId).filter(StringUtil::isNotEmpty).collect(Collectors.toList());
if (CollUtil.isNotEmpty(collect1)) {
collect.addAll(collect1);
}
List<AttendanceShiftSettingPeriodEntity> list1 = CollUtil.isEmpty(collect1) ? CollUtil.newArrayList() : attendanceShiftSettingPeriodService.list(new LambdaQueryWrapper<AttendanceShiftSettingPeriodEntity>()
.in(AttendanceShiftSettingPeriodEntity::getShiftId, collect1).eq(AttendanceShiftSettingPeriodEntity::getDeleteMark, Boolean.FALSE));
List<AttendanceShiftSettingPeriodVo> attendanceShiftSettingPeriodVos = BeanUtil.copyToList(list1, AttendanceShiftSettingPeriodVo.class);
Map<String, List<AttendanceShiftSettingPeriodVo>> periodMap = attendanceShiftSettingPeriodVos.stream().collect(Collectors.groupingBy(AttendanceShiftSettingPeriodVo::getShiftId));
List<AttendanceShiftNameEntity> attendanceShiftNameEntities = CollUtil.isEmpty(collect) ? CollUtil.newArrayList() : attendanceShiftNameSettingService.listByIds(collect);
Map<String, AttendanceShiftNameEntity> shiftMap = attendanceShiftNameEntities.stream().collect(Collectors.toMap(AttendanceShiftNameEntity::getId, entity -> entity));
dailyRuleResultVos.stream().collect(Collectors.groupingBy(DailyRuleResultVo::getDate)).forEach((day, dailyRuleVos) -> {
//旧班次名称
String oldShiftName = "";
//新班次名称
String newShiftName = "";
//新班次时间
String newShift = "";
Map<Integer, List<DailyRuleResultVo>> collect2 = dailyRuleVos.stream()
.sorted(Comparator.comparing(vo -> Objects.isNull(vo.getToSchedulesType()) ? 1 : vo.getToSchedulesType()))
.collect(Collectors.groupingBy(vo -> Objects.isNull(vo.getToSchedulesType()) ? 1 : vo.getToSchedulesType()));
int size = collect2.size();
int i = 0;
for (Map.Entry<Integer, List<DailyRuleResultVo>> stringListEntry : collect2.entrySet()) {
DailyRuleResultVo dailyRuleVo = stringListEntry.getValue().get(0);
AttendanceShiftNameEntity toShiftEntity = shiftMap.getOrDefault(dailyRuleVo.getToShiftId(), null);
newShiftName += (newShiftName.length() > 0 ? " | " : "") + (Objects.equals(dailyRuleVo.getToType(), AttendanceTypeEnum.ORDINARY.getCode()) ? Objects.isNull(toShiftEntity) ? "" : toShiftEntity.getShortName() : Objects.isNull(dailyRuleVo.getToType()) ? "" : AttendanceTypeEnum.getMsg(dailyRuleVo.getToType()));
List<AttendanceShiftSettingPeriodVo> attendanceShiftSettingPeriodVos1 = periodMap.get(dailyRuleVo.getToShiftId());
if (CollUtil.isEmpty(attendanceShiftSettingPeriodVos1) || !Objects.equals(dailyRuleVo.getToType(), AttendanceTypeEnum.ORDINARY.getCode())) {
i++;
continue;
}
if (size < 2) {
for (AttendanceShiftSettingPeriodVo attendanceShiftSettingPeriodVo : attendanceShiftSettingPeriodVos1) {
newShift += (newShift.length() > 0 ? " | " : "") + attendanceShiftSettingPeriodVo.getInPoint() + "" + attendanceShiftSettingPeriodVo.getOutPoint();
}
continue;
}
if (i == 0) {
AttendanceShiftSettingPeriodVo attendanceShiftSettingPeriodVo = attendanceShiftSettingPeriodVos1.stream().findFirst().orElse(null);
newShift = attendanceShiftSettingPeriodVo.getInPoint() + "" + attendanceShiftSettingPeriodVo.getOutPoint();
} else {
AttendanceShiftSettingPeriodVo attendanceShiftSettingPeriodVo = attendanceShiftSettingPeriodVos1.stream().reduce((p1, p2) -> p2).orElse(null);
newShift += (newShift.length() > 0 ? " | " : "") + attendanceShiftSettingPeriodVo.getInPoint() + "" + attendanceShiftSettingPeriodVo.getOutPoint();
}
i++;
}
Map<Integer, List<DailyRuleResultVo>> collect3 = dailyRuleVos.stream()
.sorted(Comparator.comparing(vo -> Objects.isNull(vo.getFromSchedulesType()) ? 1 : vo.getFromSchedulesType()))
.collect(Collectors.groupingBy(vo -> Objects.isNull(vo.getFromSchedulesType()) ? 1 : vo.getFromSchedulesType()));
for (Map.Entry<Integer, List<DailyRuleResultVo>> stringListEntry : collect3.entrySet()) {
DailyRuleResultVo dailyRuleVo = stringListEntry.getValue().stream().findFirst().orElse(null);
if (collect2.containsKey(stringListEntry.getKey())) {
List<DailyRuleResultVo> dailyRuleResultVos1 = collect2.get(stringListEntry.getKey());
List<DailyRuleResultVo> collect4 = dailyRuleResultVos1.stream().filter(result -> StringUtil.equals(result.getToId(), dailyRuleVo.getFromId())).collect(Collectors.toList());
if (CollUtil.isNotEmpty(collect4)) {
continue;
}
}
AttendanceShiftNameEntity fromShiftEntity = shiftMap.getOrDefault(dailyRuleVo.getFromShiftId(), null);
oldShiftName += (oldShiftName.length() > 0 ? " | " : "") + (Objects.equals(dailyRuleVo.getFromType(), AttendanceTypeEnum.ORDINARY.getCode()) && Objects.nonNull(fromShiftEntity) ? fromShiftEntity.getShortName() : Objects.isNull(dailyRuleVo.getFromType()) ? "" : AttendanceTypeEnum.getMsg(dailyRuleVo.getFromType()));
}
shiftChangModels.add(ShiftChangModel.builder().day(day).oldShiftName(oldShiftName).newShiftName(newShiftName).newShift(newShift).build());
});
return shiftChangModels.stream().sorted(Comparator.comparing(ShiftChangModel::getDay)).collect(Collectors.toList());
}
@Override
public List<String> getRecipient(ShiftChangeNoticeModel attendanceNoticeModel) {
return CollUtil.newArrayList(attendanceNoticeModel.getUserId());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(ShiftChangeNoticeModel attendanceNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
objects.add(JumpUrl.builder().url(String.format(ATTENDANCE_NOTICE_SHIFT_CHANGE_DETAIL_URL, noticeId)).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(ATTENDANCE_NOTICE_CLICK_URL).urlName(ATTENDANCE_NOTICE_TO_CLICK).color(COLOR_BLUE).build());
return SystemNoticeStrategy.builder()
.title(ATTENDANCE_NOTICE_SHIFT_CHANGE_TITLE)
.noticeModuleEnum(NoticeModuleEnum.BC_BD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<ShiftChangModel> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
UserInfo user = UserProvider.getUser();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(user.getUserId()), user.getTenantId());
if (CollUtil.isEmpty(allByIds)) {
log.error("请求用户服务失败或者未查询到当前用户数据:{}", user.getUserId());
return null;
}
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
StringBuffer stringBuffer = new StringBuffer();
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("操作人:无</br>");
} else {
stringBuffer.append("操作人:").append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")</br>");
}
if (data.size() > 1) {
stringBuffer.append("变更日期:").append(StringUtil.join(data.stream().map(shiftChangModel1 -> DateUtil.format(shiftChangModel1.getDay(), "yyyy.MM.dd")).collect(Collectors.toList()), "")).append("</br>");
return stringBuffer.toString();
}
ShiftChangModel shiftChangModel = data.stream().findFirst().orElse(null);
stringBuffer.append("变更日期:").append(DateUtil.format(shiftChangModel.getDay(), "yyyy.MM.dd")).append("</br>");
stringBuffer.append("新班次名称:").append(StringUtil.isEmpty(shiftChangModel.getNewShiftName()) ? "" : shiftChangModel.getNewShiftName()).append("</br>");
stringBuffer.append("新班次时间:").append(StringUtil.isEmpty(shiftChangModel.getNewShift()) ? "" : shiftChangModel.getNewShift());
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,89 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.base.UserInfo;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroup;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.model.SystemTypeChangeModel;
import jnpf.model.attendance.model.SystemTypeChangeNoticeModel;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
import static jnpf.constants.AttendanceConstant.ATTENDANCE_NOTICE_ADMIN_RULE_CHANGE_TITLE;
import static jnpf.constants.AttendanceConstant.ATTENDANCE_NOTICE_RULE_CHANGE_TITLE;
@Component(AttendanceConstant.RULE_CHANGE_SHIFT_SYSTEM)
public class SystemTypeChangeAttendanceNotice implements AttendanceNotice<SystemTypeChangeModel, SystemTypeChangeNoticeModel> {
@Autowired
private AttendanceGroupService attendanceGroupService;
@Autowired
private UserAntifreeze userAntifreeze;
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Override
public Boolean isPass(SystemTypeChangeNoticeModel attendanceNoticeModel) {
if (!attendanceNoticeModel.getAttendanceNoticeEnum().equals(AttendanceNoticeEnum.RULE_CHANGE_SHIFT_SYSTEM)) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public List<SystemTypeChangeModel> generatingData(SystemTypeChangeNoticeModel attendanceNoticeModel) {
AttendanceGroup byId = attendanceGroupService.getById(attendanceNoticeModel.getGroupId());
return CollUtil.newArrayList(SystemTypeChangeModel.builder()
.groupName(byId.getGroupName())
.oldSystemType(Objects.equals(attendanceNoticeModel.getSystemType(), 2) ? "固定班制" : "排班制")
.newSystemType(Objects.equals(attendanceNoticeModel.getSystemType(), 1) ? "固定班制" : "排班制")
.build());
}
@Override
public List<String> getRecipient(SystemTypeChangeNoticeModel attendanceNoticeModel) {
return attendanceNoticeHandler.getRecipientForSelfAndChild(attendanceNoticeModel.getGroupId(), attendanceNoticeModel.getIsAdmin());
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(SystemTypeChangeNoticeModel attendanceNoticeModel, String noticeId) {
return SystemNoticeStrategy.builder()
.noticeModuleEnum(NoticeModuleEnum.KQZ_BD)
.title(attendanceNoticeModel.getIsAdmin() ? ATTENDANCE_NOTICE_ADMIN_RULE_CHANGE_TITLE : ATTENDANCE_NOTICE_RULE_CHANGE_TITLE)
.isConfirm(Boolean.TRUE)
.build();
}
@Override
public String getContext(List<SystemTypeChangeModel> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
UserInfo user = UserProvider.getUser();
List<PartUserInfoVo> allByIds = userAntifreeze.getAllByIds(CollUtil.newArrayList(user.getUserId()), user.getTenantId());
PartUserInfoVo partUserInfoVo = allByIds.stream().findFirst().orElse(null);
StringBuffer stringBuffer = new StringBuffer();
SystemTypeChangeModel systemTypeChangeModel = data.stream().findFirst().orElse(null);
stringBuffer.append("考勤组:").append(systemTypeChangeModel.getGroupName()).append("</br>");
if (Objects.isNull(partUserInfoVo)) {
stringBuffer.append("操作人:无</br>");
} else {
stringBuffer.append("操作人:").append(partUserInfoVo.getRealName()).append("(").append(StringUtil.isEmpty(partUserInfoVo.getOrganizeName()) ? "暂无" : partUserInfoVo.getOrganizeName()).append("-").append(StringUtil.isEmpty(partUserInfoVo.getPositionName()) ? "暂无" : partUserInfoVo.getPositionName()).append(")</br>");
}
stringBuffer.append("考勤组类型已由").append(systemTypeChangeModel.getOldSystemType()).append("改为").append(systemTypeChangeModel.getNewSystemType());
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,177 @@
package jnpf.attendance.service.handle.notice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import jnpf.attendance.antifreeze.UserAntifreeze;
import jnpf.attendance.mapper.AttendanceManagerPermissionMapper;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.AttendanceGroup;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.NoticeModuleEnum;
import jnpf.enums.attendance.UserSettingEnum;
import jnpf.model.attendance.model.JumpUrl;
import jnpf.model.attendance.model.SystemNoticeStrategy;
import jnpf.model.attendance.model.UserChangModel;
import jnpf.model.attendance.model.UserChangeNoticeModel;
import jnpf.model.attendance.vo.AttendanceGroupAdminVo;
import jnpf.permission.model.user.PartUserInfoVo;
import jnpf.util.DateUtil;
import jnpf.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static jnpf.constants.AttendanceConstant.*;
import static jnpf.enums.attendance.AttendanceNoticeEnum.*;
import static jnpf.enums.attendance.UserSettingEnum.*;
/**
* 考勤组人员变动通知
*/
@Component(AttendanceConstant.JOIN_GROUP)
public class UserChangAttendanceNotice implements AttendanceNotice<UserChangModel, UserChangeNoticeModel> {
@Autowired
private UserAntifreeze userAntifreeze;
@Resource
private AttendanceNoticeHandler attendanceNoticeHandler;
@Resource
private AttendanceManagerPermissionMapper attendanceManagerPermissionMapper;
@Autowired
private AttendanceGroupService attendanceGroupService;
@Override
public Boolean isPass(UserChangeNoticeModel attendanceNoticeModel) {
return Boolean.TRUE;
}
@Override
public List<UserChangModel> generatingData(UserChangeNoticeModel attendanceNoticeModel) {
List<UserChangModel> shiftChangModels = CollUtil.newArrayList();
String tips = "";
AttendanceGroup byId = null;
List<String> realNames = null;
if (Objects.equals(AttendanceNoticeEnum.REMOVE_USER_REMOVE_GROUP, attendanceNoticeModel.getAttendanceNoticeEnum())
|| Objects.equals(AttendanceNoticeEnum.REMOVE_USER, attendanceNoticeModel.getAttendanceNoticeEnum())) {
tips = "请尽快联系管理员加入考勤组,以确保可以使用考勤打卡";
} else {
//获取管理员
List<AttendanceGroupAdminVo> attendanceGroupAdminVos = attendanceManagerPermissionMapper.queryGroupUser(attendanceNoticeModel.getJoinGroupId());
List<String> adminUserIds = attendanceGroupAdminVos.stream().map(AttendanceGroupAdminVo::getUserId).collect(Collectors.toList());
byId = attendanceGroupService.getById(attendanceNoticeModel.getJoinGroupId());
Assert.isFalse(Objects.isNull(byId), "变更考勤组通知,未查询到考勤组信息[{}]", attendanceNoticeModel.getJoinGroupId());
List<PartUserInfoVo> allByIds = CollUtil.isEmpty(adminUserIds) ? CollUtil.newArrayList() : userAntifreeze.getAllByIds(adminUserIds, attendanceNoticeModel.getTenantId());
realNames = allByIds.stream().map(PartUserInfoVo::getRealName).collect(Collectors.toList());
}
shiftChangModels.add(UserChangModel.builder()
.type(attendanceNoticeModel.getAttendanceNoticeEnum().getCode())
.administratorList(CollUtil.isEmpty(realNames) ? "" : StringUtil.join(realNames, ""))
.joinGroup(Objects.isNull(byId) ? "" : byId.getGroupName())
.start(Objects.isNull(attendanceNoticeModel.getStart()) ? "" : DateUtil.dateToString(attendanceNoticeModel.getStart(), "yyyy年MM月dd日 HH:mm"))
.reason(getReason(attendanceNoticeModel.getAttendanceNoticeEnum(), Objects.isNull(byId) ? "" : byId.getGroupName()))
.tips(tips)
.build());
return shiftChangModels;
}
/**
* @param attendanceNoticeEnum
* @param groupName
* @return
*/
private String getReason(AttendanceNoticeEnum attendanceNoticeEnum, String groupName) {
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.JOIN_GROUP)) {
return "";
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.GROUP_CHANGE_REMOVE_JOIN_GROUP)) {
return "原考勤组已解散,已加入新考勤组!";
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.REMOVE_USER_REMOVE_GROUP)) {
return "原考勤组已解散";
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.REMOVE_USER)) {
return "已从考勤组中移除";
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.GROUP_CHANGE_PROMOTION)) {
return String.format("晋升已产生,已加入【%s】", groupName);
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.GROUP_CHANGE_TRANSFER_POSITION)) {
return String.format("调岗已产生,已加入【%s】", groupName);
}
if (Objects.equals(attendanceNoticeEnum, AttendanceNoticeEnum.GROUP_CHANGE_SECONDMENT)) {
return String.format("借调申请已通过,借调至【%s】", groupName);
}
return "";
}
@Override
public List<String> getRecipient(UserChangeNoticeModel attendanceNoticeModel) {
UserSettingEnum userSettingEnum = AttendanceNoticeEnum.JOIN_GROUP.equals(attendanceNoticeModel.getAttendanceNoticeEnum()) || REMOVE_USER.equals(attendanceNoticeModel.getAttendanceNoticeEnum()) || AttendanceNoticeEnum.REMOVE_USER_REMOVE_GROUP.equals(attendanceNoticeModel.getAttendanceNoticeEnum()) ? ATTENDANCE_SETTING_ATTENDANCE_GROUP_JOIN_LEAVE_REMINDER : ATTENDANCE_SETTING_ATTENDANCE_GROUP_CHANGE_REMINDER;
return attendanceNoticeHandler.getUserIdsForFilterStatus(attendanceNoticeModel.getUserIds(), UserSettingEnum.ATTENDANCE_SETTING_MESSAGE_RECEIVE, userSettingEnum);
}
@Override
public SystemNoticeStrategy setSystemNoticeStrategy(UserChangeNoticeModel attendanceNoticeModel, String noticeId) {
ArrayList<JumpUrl> objects = CollUtil.newArrayList();
String title = ATTENDANCE_NOTICE_GROUP_CHANGE_TITLE;
if (AttendanceNoticeEnum.JOIN_GROUP.equals(attendanceNoticeModel.getAttendanceNoticeEnum())) {
title = ATTENDANCE_NOTICE_JOIN_GROUP_CHANGE_TITLE;
objects.add(JumpUrl.builder().url(ATTENDANCE_NOTICE_RULE_URL).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(ATTENDANCE_NOTICE_CLICK_URL).urlName(ATTENDANCE_NOTICE_TO_CLICK).color(COLOR_BLUE).build());
} else if (REMOVE_USER.equals(attendanceNoticeModel.getAttendanceNoticeEnum())) {
title = ATTENDANCE_NOTICE_REMOVE_USER_TITLE;
objects.add(JumpUrl.builder().url(String.format(ATTENDANCE_NOTICE_GROUP_CHANGES_URL, noticeId)).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
} else if (REMOVE_USER_REMOVE_GROUP.equals(attendanceNoticeModel.getAttendanceNoticeEnum())) {
title = ATTENDANCE_NOTICE_REMOVE_USER_TITLE;
objects.add(JumpUrl.builder().url(String.format(ATTENDANCE_NOTICE_GROUP_CHANGES_URL, noticeId)).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
} else {
objects.add(JumpUrl.builder().url(ATTENDANCE_NOTICE_RULE_URL).urlName(ATTENDANCE_NOTICE_DETAIL_BUTTON_NAME).color(COLOR_BLACK).build());
objects.add(JumpUrl.builder().url(ATTENDANCE_NOTICE_CLICK_URL).urlName(ATTENDANCE_NOTICE_TO_CLICK).color(COLOR_BLUE).build());
}
return SystemNoticeStrategy.builder()
.title(title)
.noticeModuleEnum(NoticeModuleEnum.KQZ_BD)
.jumpUrls(objects)
.build();
}
@Override
public String getContext(List<UserChangModel> data) {
if (CollUtil.isEmpty(data)) {
return null;
}
StringBuffer stringBuffer = new StringBuffer();
UserChangModel shiftChangModel = data.stream().findFirst().orElse(null);
if (StringUtil.isNotEmpty(shiftChangModel.getReason())) {
stringBuffer.append("变动原因:").append(shiftChangModel.getReason()).append("</br>");
}
if (AttendanceNoticeEnum.JOIN_GROUP.getCode().equals(shiftChangModel.getType())) {
stringBuffer.append("加入考勤组:").append(shiftChangModel.getJoinGroup()).append("</br>");
stringBuffer.append("考勤组管理员:").append(StringUtil.isNotEmpty(shiftChangModel.getAdministratorList()) ? shiftChangModel.getAdministratorList() : "暂无管理员").append("</br>");
}
if (AttendanceNoticeEnum.GROUP_CHANGE_REMOVE_JOIN_GROUP.getCode().equals(shiftChangModel.getType())) {
stringBuffer.append("新考勤组:").append(shiftChangModel.getJoinGroup()).append("</br>");
stringBuffer.append("考勤组管理员:").append(StringUtil.isNotEmpty(shiftChangModel.getAdministratorList()) ? shiftChangModel.getAdministratorList() : "暂无管理员").append("</br>");
}
if (AttendanceNoticeEnum.GROUP_CHANGE_SECONDMENT.getCode().equals(shiftChangModel.getType())) {
stringBuffer.append("开始时间:").append(shiftChangModel.getStart()).append("</br>");
}
if (AttendanceNoticeEnum.GROUP_CHANGE_TRANSFER_POSITION.getCode().equals(shiftChangModel.getType())
|| AttendanceNoticeEnum.GROUP_CHANGE_PROMOTION.getCode().equals(shiftChangModel.getType())) {
stringBuffer.append("考勤组管理员:").append(StringUtil.isNotEmpty(shiftChangModel.getAdministratorList()) ? shiftChangModel.getAdministratorList() : "暂无管理员").append("</br>");
}
if (StringUtil.isNotEmpty(shiftChangModel.getTips())) {
stringBuffer.append(shiftChangModel.getTips());
}
return stringBuffer.toString();
}
}

View File

@@ -0,0 +1,328 @@
package jnpf.attendance.service.handle.notification;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import jnpf.attendance.service.AttendanceClockInService;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.attendance.service.DailyRuleChangeService;
import jnpf.attendance.service.handle.notice.AttendanceNoticeHandler;
import jnpf.base.UserInfo;
import jnpf.constants.MessageTopicConstants;
import jnpf.entity.attendance.DailyRuleChange;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceNoticeEnum;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.TriggerSceneEnum;
import jnpf.model.attendance.dto.LineDrawingPeriodDto;
import jnpf.model.attendance.dto.LineDrawingSchedulesConfigDto;
import jnpf.model.attendance.event.StatisticsBatchClearDto;
import jnpf.model.attendance.event.StatisticsSingleDto;
import jnpf.model.attendance.model.LineShiftChangeNoticeModel;
import jnpf.model.attendance.model.ShiftChangeNoticeModel;
import jnpf.model.attendance.model.SystemTypeChangeNoticeModel;
import jnpf.model.attendance.vo.AttendanceShiftSettingVo;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import jnpf.model.attendance.vo.UserDayVo;
import jnpf.util.DateDetail;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import jnpf.util.attendance.DailyRuleUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
@Slf4j
public class AttendanceRuleNotificationHandle {
@Resource
private RocketMQTemplate rocketMqTemplate;
@Autowired
private AttendanceClockInService attendanceClockInService;
@Autowired
private AttendanceNoticeHandler attendanceNoticeHandler;
@Autowired
private DailyRuleChangeService dailyRuleChangeService;
public void notificationHandle(List<DailyRuleResultVo> resultList, String tenantId, Boolean isSync, Boolean isNotificationClock) {
UserInfo user = UserProvider.getUser();
if (StringUtil.isNotNull(tenantId)) {
user.setTenantId(tenantId);
}
if (isSync) {
notificationClockHandleSync(resultList, user, isNotificationClock);
return;
}
notificationMqHandle(resultList, user, isNotificationClock);
}
public void notificationHandle(List<DailyRuleResultVo> resultList, Boolean isSync, Boolean isNotificationClock) {
notificationHandle(resultList, null, isSync, isNotificationClock);
}
public void notificationHandle(List<DailyRuleResultVo> resultList, Boolean isSync) {
notificationHandle(resultList, isSync, Boolean.TRUE);
}
public void notificationHandle(List<DailyRuleResultVo> resultList, String tenantId) {
notificationHandle(resultList, tenantId, Boolean.FALSE, Boolean.TRUE);
}
public void notificationClearHandle(String tenantId, String fromGroupId, List<String> userIds, Date day) {
if (CollUtil.isEmpty(userIds)) {
return;
}
//调用批量清除日统计数据接口s
StatisticsBatchClearDto batchClearDto = StatisticsBatchClearDto.builder()
.tenantId(StringUtil.isEmpty(tenantId) ? UserProvider.getUser().getTenantId() : tenantId)
.groupId(fromGroupId)
.userIdList(userIds)
.startDay(day)
.build();
Message<StatisticsBatchClearDto> clearMessage = MessageBuilder.withPayload(batchClearDto).build();
rocketMqTemplate.syncSend(MessageTopicConstants.ATTENDANCE_STATISTICS_BATCH_CLEAR_TOPIC, clearMessage, 3000L, 2);
}
/**
* 规则变动发送通知
*
* @param resultList 规则变动结果
* @param tenantId 租户id
*/
@Async("threadPoolTaskExecutor")
public void sendSystemNotice(List<DailyRuleResultVo> resultList, String tenantId) {
resultList.stream()
.filter(dailyRuleResultVo -> Objects.nonNull(dailyRuleResultVo.getFromType())
&& (Objects.equals(dailyRuleResultVo.getFromType(), AttendanceTypeEnum.ORDINARY.getCode())
|| Objects.equals(dailyRuleResultVo.getFromType(), AttendanceTypeEnum.REST.getCode())
|| Objects.equals(dailyRuleResultVo.getFromType(), AttendanceTypeEnum.HOLIDAYS.getCode())
|| Objects.equals(dailyRuleResultVo.getFromType(), AttendanceTypeEnum.DEDUCTION_HOLIDAYS.getCode())
|| Objects.equals(dailyRuleResultVo.getFromType(), AttendanceTypeEnum.EXCHANGE_HOLIDAYS.getCode()))
&& (Objects.equals(dailyRuleResultVo.getToType(), AttendanceTypeEnum.ORDINARY.getCode())
|| Objects.equals(dailyRuleResultVo.getToType(), AttendanceTypeEnum.REST.getCode())
|| Objects.equals(dailyRuleResultVo.getToType(), AttendanceTypeEnum.HOLIDAYS.getCode())
|| Objects.equals(dailyRuleResultVo.getToType(), AttendanceTypeEnum.DEDUCTION_HOLIDAYS.getCode())
|| Objects.equals(dailyRuleResultVo.getToType(), AttendanceTypeEnum.EXCHANGE_HOLIDAYS.getCode())
|| Objects.isNull(dailyRuleResultVo.getToType()))).collect(Collectors.groupingBy(DailyRuleResultVo::getUserId))
.forEach((userId, results) -> {
ShiftChangeNoticeModel shiftChangeNoticeModel = new ShiftChangeNoticeModel();
shiftChangeNoticeModel.setTenantId(StringUtil.isEmpty(tenantId) ? UserProvider.getUser().getTenantId() : tenantId);
shiftChangeNoticeModel.setUserId(userId);
shiftChangeNoticeModel.setDailyRuleResultVos(results);
shiftChangeNoticeModel.setAttendanceNoticeEnum(AttendanceNoticeEnum.SHIFT_CHANG);
attendanceNoticeHandler.send(shiftChangeNoticeModel);
});
}
@Async("threadPoolTaskExecutor")
public void sendNoticeBatch(List<String> selfAndChildrenGroupIds, Integer systemType) {
selfAndChildrenGroupIds.forEach(itemGroupId -> sendNotice(itemGroupId, systemType));
}
private void sendNotice(String groupId, Integer systemType) {
SystemTypeChangeNoticeModel systemTypeChangeNoticeModel = new SystemTypeChangeNoticeModel();
systemTypeChangeNoticeModel.setSystemType(systemType);
systemTypeChangeNoticeModel.setGroupId(groupId);
systemTypeChangeNoticeModel.setIsAdmin(Boolean.FALSE);
systemTypeChangeNoticeModel.setTenantId(UserProvider.getUser().getTenantId());
systemTypeChangeNoticeModel.setAttendanceNoticeEnum(AttendanceNoticeEnum.RULE_CHANGE_SHIFT_SYSTEM);
attendanceNoticeHandler.send(systemTypeChangeNoticeModel);
systemTypeChangeNoticeModel.setIsAdmin(Boolean.TRUE);
attendanceNoticeHandler.send(systemTypeChangeNoticeModel);
}
public void sendSystemNoticeForLine(List<DailyRuleResultVo> resultList, LineDrawingSchedulesConfigDto configDto, String tenantId) {
sendSystemNoticeForLine(resultList, configDto, null, tenantId);
}
/**
* 划线排班规则变动发送通知
*
* @param configDto 规则
* @param tenantId 租户id
*/
public void sendSystemNoticeForLine(List<DailyRuleResultVo> resultList, LineDrawingSchedulesConfigDto configDto, List<Date> days, String tenantId) {
LineShiftChangeNoticeModel shiftChangeNoticeModel = new LineShiftChangeNoticeModel();
shiftChangeNoticeModel.setAttendanceNoticeEnum(AttendanceNoticeEnum.LINE_SHIFT_CHANG);
shiftChangeNoticeModel.setTenantId(StringUtil.isEmpty(tenantId) ? UserProvider.getUser().getTenantId() : tenantId);
List<Date> daysList = CollUtil.isNotEmpty(days) ? days : Arrays.stream(StringUtil.split(configDto.getDays(), ",")).map(jnpf.util.DateUtil::stringToDates).collect(Collectors.toList());
Map<String, List<DailyRuleResultVo>> collect = resultList.stream().collect(Collectors.groupingBy(vo -> vo.getUserId() + DateDetail.getDate2Str(vo.getDate(), DateDetail.DF)));
configDto.getUserList()
.forEach(user -> {
List<LineDrawingPeriodDto> periods = user.getPeriods();
if (CollUtil.isEmpty(periods) && CollUtil.isEmpty(resultList)) {
return;
}
if (CollUtil.isNotEmpty(periods) && periods.stream().allMatch(vo -> StringUtil.isNotEmpty(vo.getId()))) {
return;
}
List<LineDrawingPeriodDto> periodList = CollUtil.newArrayList();
List<Date> collect1 = periods.stream().map(LineDrawingPeriodDto::getDay).distinct().sorted().collect(Collectors.toList());
if (CollUtil.isEmpty(collect1)) {
collect1 = daysList;
}
collect1.forEach(day -> {
String key = user.getUserId() + DateDetail.getDate2Str(day, DateDetail.DF);
if (!collect.containsKey(key)) {
return;
}
if (CollUtil.isEmpty(periods)) {
periodList.add(LineDrawingPeriodDto.builder()
.day(day)
.start("")
.build());
return;
}
periodList.addAll(BeanUtil.copyToList(periods, LineDrawingPeriodDto.class).stream().peek(vo -> vo.setDay(day)).collect(Collectors.toList()));
});
if (CollUtil.isEmpty(periodList)) {
return;
}
shiftChangeNoticeModel.setUserIds(List.of(user.getUserId()));
shiftChangeNoticeModel.setPeriods(periodList);
attendanceNoticeHandler.send(shiftChangeNoticeModel);
});
}
/**
* 划线排班规则变动发送通知
*
* @param rules 规则
* @param tenantId 租户id
*/
@Async("threadPoolTaskExecutor")
public void sendSystemNoticeForLine2(List<DailyRuleResultVo> resultList, List<FtbAttendanceDailyRule> rules, String tenantId) {
Map<String, List<DailyRuleResultVo>> collect = resultList.stream().collect(Collectors.groupingBy(vo -> vo.getUserId() + DateDetail.getDate2Str(vo.getDate(), DateDetail.DF)));
LineShiftChangeNoticeModel shiftChangeNoticeModel = new LineShiftChangeNoticeModel();
shiftChangeNoticeModel.setTenantId(StringUtil.isEmpty(tenantId) ? UserProvider.getUser().getTenantId() : tenantId);
shiftChangeNoticeModel.setAttendanceNoticeEnum(AttendanceNoticeEnum.LINE_SHIFT_CHANG);
rules.stream().filter(vo -> Objects.equals(vo.getAttendanceType(), AttendanceTypeEnum.LEAVE.getCode()) || Objects.equals(vo.getAttendanceType(), AttendanceTypeEnum.ORDINARY.getCode())).collect(Collectors.groupingBy(rule -> rule.getUserId() + DateDetail.getDate2Str(rule.getDay(), DateDetail.DF)))
.forEach((key, userRules) -> {
FtbAttendanceDailyRule rule = userRules.stream().findFirst().orElse(null);
if (Objects.isNull(rule)) {
return;
}
if (!collect.containsKey(key)) {
return;
}
DateTime tomorrow = DateUtil.offsetDay(rule.getDay(), 1);
List<DailyRuleResultVo> orDefault = collect.getOrDefault(key, List.of());
boolean isClear = orDefault.stream().allMatch(vo -> Objects.isNull(vo.getType()));
List<LineDrawingPeriodDto> periods = DailyRuleUtil.mergeRules(userRules).stream().map(dayRule -> LineDrawingPeriodDto.builder()
.day(dayRule.getDay())
.startType(dayRule.getInPoint().after(tomorrow) ? 2 : 1)
.start(isClear ? "" : jnpf.util.DateUtil.dateToString(dayRule.getInPoint(), "HH:mm"))
.startType(dayRule.getOutPoint().after(tomorrow) ? 2 : 1)
.end(isClear ? "" : jnpf.util.DateUtil.dateToString(dayRule.getOutPoint(), "HH:mm"))
.build()).collect(Collectors.toList());
shiftChangeNoticeModel.setUserIds(List.of(rule.getUserId()));
shiftChangeNoticeModel.setPeriods(periods);
shiftChangeNoticeModel.setDay(rule.getDay());
attendanceNoticeHandler.send(shiftChangeNoticeModel);
});
}
private void notificationClockHandleSync(List<DailyRuleResultVo> resultList, UserInfo user, boolean isNotificationClock) {
if (isNotificationClock) {
try {
// 出勤变更通知
List<UserDayVo> userDayList = resultList.stream()
.map(vo -> new UserDayVo(user.getTenantId(), vo.getGroupId(), vo.getUserId(), vo.getDate(), DateDetail.getDate2Str(vo.getDate(), DateDetail.DF)))
.collect(Collectors.collectingAndThen(
// 去除重复记录, 冲突时保留第一条
Collectors.toMap(u -> u.getUserId() + "_" + u.getDayStr(), Function.identity(), (existing, replacement) -> existing),
map -> new ArrayList<>(map.values())
));
dailyRuleChangeService.saveRecordBatch(userDayList.stream().map(userDayVo -> new DailyRuleChange(userDayVo.getGroupId(), userDayVo.getUserId(), userDayVo.getDay(), userDayVo.getTenantId())).collect(Collectors.toList()));
attendanceClockInService.changeAttendanceRuleBatch(userDayList, user);
} catch (Exception e) {
log.error("排班通知打卡失败", e);
}
}
//调用批量生成日统计数据接口
Map<String, List<DailyRuleResultVo>> groupMap = resultList.stream().collect(Collectors.groupingBy(DailyRuleResultVo::getGroupId));
groupMap.forEach((groupId, dayList) -> {
Map<Date, List<DailyRuleResultVo>> dayMap = dayList.stream().collect(Collectors.groupingBy(DailyRuleResultVo::getDate));
dayMap.forEach((date, userList) -> {
notificationClearHandle(user.getTenantId(), groupId, userList.stream().filter(vo -> Objects.isNull(vo.getToType())).map(DailyRuleResultVo::getUserId).distinct().collect(Collectors.toList()), date);
notificationStatistics(user.getTenantId(), groupId, date, userList.stream().map(DailyRuleResultVo::getUserId).distinct().collect(Collectors.toList()));
});
});
}
private void notificationMqHandle(List<DailyRuleResultVo> resultList, UserInfo user, boolean isNotificationClock) {
if (isNotificationClock) {
notificationClockMq(resultList, user);
}
//调用批量生成日统计数据接口
Map<String, List<DailyRuleResultVo>> groupMap = resultList.stream().collect(Collectors.groupingBy(DailyRuleResultVo::getGroupId));
groupMap.forEach((groupId, dayList) -> {
Map<Date, List<DailyRuleResultVo>> dayMap = dayList.stream().collect(Collectors.groupingBy(DailyRuleResultVo::getDate));
dayMap.forEach((date, userList) -> {
notificationClearHandle(user.getTenantId(), groupId, userList.stream().filter(vo -> Objects.isNull(vo.getToType())).map(DailyRuleResultVo::getUserId).distinct().collect(Collectors.toList()), date);
notificationStatistics(user.getTenantId(), groupId, date, userList.stream().map(DailyRuleResultVo::getUserId).distinct().collect(Collectors.toList()));
});
});
}
public void notificationClockMq(List<DailyRuleResultVo> resultList, UserInfo user) {
//调用生成日统计数据接口
// 出勤变更通知
List<UserDayVo> userDayList = resultList.stream()
.map(vo -> new UserDayVo(user.getTenantId(), vo.getGroupId(), vo.getUserId(), vo.getDate(), DateDetail.getDate2Str(vo.getDate(), DateDetail.DF)))
.collect(Collectors.collectingAndThen(
// 去除重复记录, 冲突时保留第一条
Collectors.toMap(u -> u.getUserId() + "_" + u.getDayStr(), Function.identity(), (existing, replacement) -> existing),
map -> new ArrayList<>(map.values())
));
Message<List<UserDayVo>> message = MessageBuilder.withPayload(userDayList).build();
try {
dailyRuleChangeService.saveRecordBatch(userDayList.stream().map(userDayVo -> new DailyRuleChange(userDayVo.getGroupId(), userDayVo.getUserId(), userDayVo.getDay(), userDayVo.getTenantId())).collect(Collectors.toList()));
SendResult sendResult = rocketMqTemplate.syncSend(MessageTopicConstants.ATTENDANCE_NOTIFICATION_CLOCK_TOPIC, message, 3000L, 3);
Assert.isFalse(!sendResult.getSendStatus().equals(SendStatus.SEND_OK), "排班通知打卡异常重试");
} catch (Exception e) {
log.error("AttendanceRuleNotificationHandle#notificationClockMq 排班通知打卡异常:{}", JSON.toJSONString(message), e);
throw new RuntimeException("排班通知打卡异常", e);
}
}
public void notificationStatistics(String tenantId, String groupId, Date date, List<String> userList) {
//调用生成日统计数据接口
StatisticsSingleDto courseEventDTO = StatisticsSingleDto.builder()
.tenantId(tenantId)
.groupId(groupId)
.day(date)
.triggerSceneEnum(TriggerSceneEnum.SCHEDULES)
.build();
userList.forEach(item -> {
courseEventDTO.setUserId(item);
Message<StatisticsSingleDto> message = MessageBuilder.withPayload(courseEventDTO).build();
if (StrUtil.isBlank(tenantId) || StrUtil.isBlank(groupId)) {
log.error("AttendanceRuleNotificationHandle#notificationStatistics 触发日统计租户ID或者考勤组ID为空{}", JSON.toJSONString(courseEventDTO));
return;
}
rocketMqTemplate.syncSend(MessageTopicConstants.ATTENDANCE_STATISTICS_SINGLE_TOPIC, message, 3000L, 2);
});
}
}

View File

@@ -0,0 +1,206 @@
package jnpf.attendance.service.handle.notification;
import jnpf.config.CustomTenantUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
@Component
@Slf4j
public class MultiTenantTimeSizeBatchProcessor<T> {
// 租户处理器映射
private final Map<String, TenantBatchHandler<T>> tenantHandlers = new ConcurrentHashMap<>();
// 共享资源管理
private final TenantResourceManager tenantResourceManager;
private final CustomTenantUtil customTenantUtil;
// 定期清理不活跃租户的调度器
private final ScheduledExecutorService cleanupScheduler = Executors.newScheduledThreadPool(1);
public MultiTenantTimeSizeBatchProcessor(
TenantResourceManager tenantResourceManager,
CustomTenantUtil customTenantUtil) {
this.tenantResourceManager = tenantResourceManager;
this.customTenantUtil = customTenantUtil;
// 启动定期清理任务
cleanupScheduler.scheduleAtFixedRate(
this::cleanupInactiveHandlers, 30, 30, TimeUnit.MINUTES);
}
/**
* 添加数据到批处理队列
* @param tenantId 租户ID
* @param data 要处理的数据
*/
public void addData(String tenantId, T data) {
// 获取或创建租户处理器
TenantBatchHandler<T> handler = tenantHandlers.computeIfAbsent(
tenantId,
id -> new TenantBatchHandler<>(id, tenantResourceManager, customTenantUtil)
);
// 添加数据到处理器
handler.addData(data);
}
/**
* 清理不活跃的租户处理器
*/
private void cleanupInactiveHandlers() {
long currentTime = System.currentTimeMillis();
long inactiveThreshold = 30 * 60 * 1000; // 30分钟不活跃
tenantHandlers.entrySet().removeIf(entry -> {
TenantBatchHandler<T> handler = entry.getValue();
if (currentTime - handler.getLastActiveTime() > inactiveThreshold) {
handler.cleanup();
log.info("Cleaned up inactive tenant handler: {}", entry.getKey());
return true;
}
return false;
});
}
@PreDestroy
public void shutdown() {
cleanupScheduler.shutdown();
tenantHandlers.values().forEach(TenantBatchHandler::cleanup);
log.info("MultiTenantTimeSizeBatchProcessor shutdown completed");
}
/**
* 租户专用批处理器 - 实现时间和数量双重触发机制
*/
private static class TenantBatchHandler<T> {
// 数据缓冲区
private final List<T> buffer = new ArrayList<>();
private final Object lock = new Object();
// 定时器管理
private final ScheduledExecutorService scheduler;
private ScheduledFuture<?> currentTimer;
// 租户信息
private final String tenantId;
private final TenantResourceManager tenantResourceManager;
private final CustomTenantUtil customTenantUtil;
@Getter
private volatile long lastActiveTime;
// 批处理配置 - 根据租户规模动态调整
private final int batchSize;
private final long timeInterval;
public TenantBatchHandler(String tenantId,
TenantResourceManager tenantResourceManager,
CustomTenantUtil customTenantUtil) {
this.tenantId = tenantId;
this.tenantResourceManager = tenantResourceManager;
this.customTenantUtil = customTenantUtil;
this.lastActiveTime = System.currentTimeMillis();
// 为小租户优化配置
this.batchSize = 50; // 小批次
this.timeInterval = 3000; // 3秒超时
// 创建专用调度器
this.scheduler = Executors.newSingleThreadScheduledExecutor(
r -> new Thread(r, "tenant-" + tenantId + "-batch-scheduler"));
}
/**
* 添加数据到批处理队列
*/
public void addData(T data) {
synchronized (lock) {
buffer.add(data);
lastActiveTime = System.currentTimeMillis();
// 双重触发机制
if (buffer.size() >= batchSize) {
// 数量触发:达到批次大小立即处理
log.debug("Tenant {} batch triggered by size: {}", tenantId, buffer.size());
processBatch();
} else if (currentTimer == null || currentTimer.isDone()) {
// 时间触发:启动定时器
log.debug("Tenant {} batch timer started", tenantId);
currentTimer = scheduler.schedule(
this::processBatch, timeInterval, TimeUnit.MILLISECONDS);
}
}
}
/**
* 处理批次数据
*/
private void processBatch() {
synchronized (lock) {
if (buffer.isEmpty()) return;
// 获取当前批次数据
List<T> batch = new ArrayList<>(buffer);
buffer.clear();
// 取消当前定时器
if (currentTimer != null && !currentTimer.isDone()) {
currentTimer.cancel(false);
currentTimer = null;
}
// 使用共享线程池异步处理
CompletableFuture.runAsync(() -> {
processData(batch);
}, tenantResourceManager.getSharedThreadPool());
}
}
/**
* 实际数据处理逻辑
*/
private void processData(List<T> data) {
try {
lastActiveTime = System.currentTimeMillis();
// 关键:切换到租户数据库
customTenantUtil.checkOutTenant(tenantId);
// 执行实际的业务处理
executeBatchOperation(data);
} catch (Exception e) {
log.error("Error processing batch for tenant " + tenantId, e);
// 可以添加重试机制或死信队列处理
}
}
/**
* 执行批量数据库操作
*/
private void executeBatchOperation(List<T> data) {
try {
// 批量插入或更新操作
} catch (Exception e) {
log.error("Database operation failed for tenant " + tenantId, e);
throw new RuntimeException("Batch operation failed", e);
}
}
/**
* 清理资源
*/
public void cleanup() {
if (currentTimer != null && !currentTimer.isDone()) {
currentTimer.cancel(true);
}
scheduler.shutdown();
buffer.clear();
}
}
}

View File

@@ -0,0 +1,54 @@
package jnpf.attendance.service.handle.notification;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
@Component
@Slf4j
public class TenantResourceManager {
// 共享线程池 - 避免为每个小租户创建独立线程池
private final ThreadPoolExecutor sharedThreadPool;
public TenantResourceManager() {
// 优化的线程池配置
this.sharedThreadPool = new ThreadPoolExecutor(
20, // 核心线程数
100, // 最大线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10000), // 队列大小
new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "tenant-shared-thread-" + threadNumber.getAndIncrement());
t.setDaemon(false);
return t;
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
}
public Executor getSharedThreadPool() {
return sharedThreadPool;
}
@PreDestroy
public void shutdown() {
sharedThreadPool.shutdown();
try {
if (!sharedThreadPool.awaitTermination(30, TimeUnit.SECONDS)) {
sharedThreadPool.shutdownNow();
}
} catch (InterruptedException e) {
sharedThreadPool.shutdownNow();
Thread.currentThread().interrupt();
}
log.info("TenantResourceManager shutdown completed");
}
}

View File

@@ -0,0 +1,932 @@
package jnpf.attendance.service.handle.rule;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSON;
import jnpf.attendance.service.RuleProcessor;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.entity.attendance.LeaveParam;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.LeaveUnitEnum;
import jnpf.enums.attendance.v2.WorkBoundaryCoverageEnum;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import jnpf.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
/**
* 处理历史请假申请
*/
@Component
@Slf4j
public class LeaveRuleProcessor extends RuleProcessor {
@Override
public void ruleArrangementHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> currDailyRule, List<DailyRuleResultVo> resultList) {
Map<Integer, List<FtbAttendanceDailyRule>> collect = hisDailyRules.stream().collect(Collectors.groupingBy(FtbAttendanceDailyRule::getAttendanceType));
List<FtbAttendanceDailyRule> ftbAttendanceDailyRules = collect.getOrDefault(AttendanceTypeEnum.LEAVE.getCode(), List.of()).stream().filter(rule -> Objects.isNull(rule.getIsInsert()) || !rule.getIsInsert()).collect(Collectors.toList());
if (CollUtil.isNotEmpty(ftbAttendanceDailyRules)) {
Iterator<FtbAttendanceDailyRule> iterator = currDailyRule.iterator();
while (iterator.hasNext()) {
FtbAttendanceDailyRule rule = iterator.next();
//新增排休
if (restHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增上班
if (ordinaryHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增加班
if (workOvertimeHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增请假
if (leaveHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增出差、外出
if (stepOutHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增清除
clearHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList);
}
}
if (Objects.nonNull(nextRuleProcessor)) {
nextRuleProcessor.ruleArrangementHandle(hisDailyRules, currDailyRule, resultList);
}
}
private Boolean clearHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增清除
if (!Objects.equals(AttendanceTypeEnum.CLEAR.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
oldRule.setShiftId("");
oldRule.setInPoint(oldRule.getApplyStart());
oldRule.setOutPoint(oldRule.getApplyEnd());
oldRule.setApplyViewEnable(2);
oldRule.setLeaveDay(BigDecimal.ZERO);
oldRule.setPayrollHours(BigDecimal.ZERO);
oldRule.setValidDuration(0);
});
return Boolean.TRUE;
}
/**
* 新增外出、出差申请
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean stepOutHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增外出、出差申请
if (!Objects.equals(AttendanceTypeEnum.BUSINESS_TRIP.getCode(), rule.getAttendanceType()) && !Objects.equals(AttendanceTypeEnum.STEP_OUT.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//过滤隐藏规则
if (Objects.equals(oldRule.getApplyViewEnable(), 0)) {
return;
}
rule.setShiftId(oldRule.getShiftId());
rule.setPeriodId(oldRule.getPeriodId());
//原小时外出没命中已有班次数据,隐藏外出申请
if (rule.getOutPoint().before(oldRule.getInPoint())
|| rule.getInPoint().after(oldRule.getOutPoint())
|| rule.getInPoint().after(oldRule.getInPoint()) && rule.getOutPoint().before(oldRule.getOutPoint())) {
if (!rule.getIsInsert()) {
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
}
log.error("新增排班数据未命中小时外出申请或者外出数据完全被排班数据覆盖,过滤{}", JSON.toJSONString(rule));
return;
}
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
rule.setApplyViewEnable(0);
oldRule.setApplyViewEnable(rule.getAttendanceType());
//原小时外出数据覆盖现在新增排班数据上班时间
if (!rule.getInPoint().after(oldRule.getInPoint())) {
oldRule.setInStepOutType(1);
oldRule.setInStepOutApplyId(rule.getApplyId());
}
//原小时外出数据覆盖现在新增排班数据下班时间
if (!rule.getOutPoint().before(oldRule.getOutPoint())) {
oldRule.setOutStepOutType(1);
oldRule.setOutStepOutApplyId(rule.getApplyId());
}
log.error("新增外出、出差申请标记原请假时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
});
return Boolean.TRUE;
}
/**
* 新增请假
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean leaveHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增请假
if (!Objects.equals(AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//新加入数据不做处理
if (oldRule.getIsInsert() || Objects.equals(rule.getId(), oldRule.getId())) {
return;
}
if (!Objects.equals(LeaveUnitEnum.HOUR.getCode(), rule.getApplyUnit()) || !Objects.equals(LeaveUnitEnum.HOUR.getCode(), oldRule.getApplyUnit())) {
if (isLeaveDateConflict(rule, oldRule)) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.LEAVE));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType()));
return;
}
return;
}
//如果当前申请的请假单位为天或者半天,原班次存在单位为小时的请假,则直接提示
Assert.isFalse(isLeaveDateConflict(rule, oldRule) || isLeaveDateConflict(oldRule, rule), "当前请假时间与原请假时间冲突");
//请假单位非小时,不走下述逻辑
if (Objects.nonNull(rule.getApplyUnit()) && !Objects.equals(rule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode())) {
return;
}
rule.setShiftId(oldRule.getShiftId());
rule.setPeriodId(oldRule.getPeriodId());
//新增请假时间完全覆盖原来请假时段
if (DateDetail.checkTimeBetween(oldRule.getApplyStart(), rule.getApplyStart(), rule.getApplyEnd())
&& DateDetail.checkTimeBetween(oldRule.getApplyEnd(), rule.getApplyStart(), rule.getApplyEnd())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.LEAVE));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType()));
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkBetween(rule.getApplyEnd(), oldRule.getApplyStart(), oldRule.getApplyEnd())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.LEAVE));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType()));
return;
}
//结束部分覆盖
if (DateDetail.checkBetween(rule.getApplyStart(), oldRule.getApplyStart(), oldRule.getApplyEnd())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.LEAVE));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType()));
return;
}
//新增请假时段处于原请假时段中间
if (DateDetail.checkTimeBetweenL(rule.getApplyStart(), oldRule.getApplyStart(), oldRule.getApplyEnd())
&& DateDetail.checkTimeBetweenR(rule.getApplyEnd(), oldRule.getApplyStart(), oldRule.getApplyEnd())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.LEAVE));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType()));
return;
}
//请假与请假时间边界连接
//请假结束时间与原请假开始时间相同
if (oldRule.getInPoint().compareTo(rule.getApplyEnd()) == 0) {
oldRule.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
rule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
}
//请假开始时间与原请假时段结束时间相同
if (oldRule.getOutPoint().compareTo(rule.getApplyStart()) == 0) {
oldRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
rule.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
}
if (!hisDailyRules.contains(rule) && !rule.getIsInsert()) {
hisDailyRules.add(rule);
log.error("新增请假时段与原请假时段没交集{}", JSON.toJSONString(rule));
}
});
return Boolean.TRUE;
}
/**
* 判断修改后的规则是否与旧规则在请假时间上存在冲突
* 此方法专门用于检查是否存在请假日期冲突,即旧规则设置为请假,而新规则不设置为请假的情况
* 这种冲突检测对于确保考勤政策的一致性和准确性至关重要
*
* @param rule 新的考勤日常规则对象,包含修改后的规则信息
* @param oldRule 旧的考勤日常规则对象,包含修改前的规则信息
* @return 如果存在请假日期冲突则返回true否则返回false
*/
private boolean isLeaveDateConflict(FtbAttendanceDailyRule rule, FtbAttendanceDailyRule oldRule) {
if (oldRule.getIsInsert()) {
return Boolean.FALSE;
}
if (!Objects.equals(rule.getApplyUnit(), oldRule.getApplyUnit())) {
log.error("新增请假与原请假时间冲突");
return Boolean.TRUE;
}
//新增请假不是全天且不是半天,则过滤
if (Objects.equals(rule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode()) || Objects.isNull(rule.getApplyUnit())) {
return Boolean.FALSE;
}
// 检查旧规则是否请假单位为小时,同时新规则的请假单位不为小时,表示存在冲突
//如果原来为全天请假则冲突
if (Objects.equals(oldRule.getApplyUnit(), LeaveUnitEnum.DAY.getCode())) {
log.error("新增请假与原全天请假冲突");
return Boolean.TRUE;
}
//如果原来为全天请假则冲突
//如果原半天请假时间处于新增请假中间
LeaveParam leaveParam = JsonUtil.getJsonToBean(rule.getLeaveParam(), LeaveParam.class);
LeaveParam oldLeaveParam = JsonUtil.getJsonToBean(oldRule.getLeaveParam(), LeaveParam.class);
if (leaveParam.getStart().compareTo(oldLeaveParam.getEnd()) == 0 && oldLeaveParam.getEndTimeType() < leaveParam.getStartTimeType()) {
return Boolean.FALSE;
}
if (leaveParam.getEnd().compareTo(oldLeaveParam.getStart()) == 0 && oldLeaveParam.getStartTimeType() > leaveParam.getEndTimeType()) {
return Boolean.FALSE;
}
log.error("新增半天请假与原半天请假冲突");
return Boolean.TRUE;
}
/**
* 新增上班
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param ordinaryRule 当前规则
*/
private Boolean ordinaryHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule ordinaryRule, List<DailyRuleResultVo> resultList) {
//新增上班
if (!Objects.equals(AttendanceTypeEnum.ORDINARY.getCode(), ordinaryRule.getAttendanceType())) {
return Boolean.FALSE;
}
Set<String> seen = new HashSet<>();
hisDailyRules.removeAll(ftbAttendanceDailyRules);
List<FtbAttendanceDailyRule> ftbAttendanceDailyRules1 = ftbAttendanceDailyRules.stream()
.filter(p -> seen.add(p.getApplyId()))
.collect(Collectors.toList());
hisDailyRules.addAll(ftbAttendanceDailyRules1);
ftbAttendanceDailyRules1.stream().filter(rule1 -> !Objects.equals(rule1.getApplyUnit(), 1) && Objects.nonNull(rule1.getApplyUnit())).forEach(leaveRule -> {
daysLeaveHandle(hisDailyRules, leaveRule, ordinaryRule, resultList);
});
ftbAttendanceDailyRules1.removeIf(dailyRule -> Objects.equals(dailyRule.getAttendanceType(), AttendanceTypeEnum.LEAVE.getCode()) && !Objects.equals(dailyRule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode()));
List<FtbAttendanceDailyRule> collect = ftbAttendanceDailyRules1.stream().filter(rule1 -> Objects.equals(rule1.getApplyUnit(), 1) || Objects.isNull(rule1.getApplyUnit())).collect(Collectors.toList());
Iterator<FtbAttendanceDailyRule> leaveRuleIterator = collect.iterator();
while (leaveRuleIterator.hasNext()) {
houseLeaveHandle(hisDailyRules, ordinaryRule, leaveRuleIterator, resultList);
}
return Boolean.TRUE;
}
/**u
* 小时请假处理
*
* @param hisDailyRules
* @param ordinaryRule
* @param leaveRuleIterator
* @param resultList
*/
private void houseLeaveHandle(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule ordinaryRule, Iterator<FtbAttendanceDailyRule> leaveRuleIterator, List<DailyRuleResultVo> resultList) {
FtbAttendanceDailyRule leaveRule = leaveRuleIterator.next();
if (Objects.nonNull(leaveRule.getApplyUnit()) && !Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode())) {
return;
}
if (Objects.equals(ordinaryRule.getApplyViewEnable(), 0)) {
leaveRule.setApplyViewEnable(2);
return;
}
ordinaryRule.setSelfGroup(leaveRule.getSelfGroup());
leaveRule.setApplyViewEnable(1);
leaveRule.setFixedMark(ordinaryRule.getFixedMark());
leaveRule.setPeriodId(ordinaryRule.getPeriodId());
//新增上班时段处于原请假时段中间
if (DateDetail.checkTimeBetween(ordinaryRule.getInPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())
&& DateDetail.checkTimeBetween(ordinaryRule.getOutPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())) {
leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
leaveRule.setInPoint(ordinaryRule.getInPoint());
leaveRule.setOutPoint(ordinaryRule.getOutPoint());
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
getBreakTimeByOrdinary(leaveRule, ordinaryRule);
houseLeaveDayProcess(leaveRule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
ordinaryRule.insertTrue();
hisDailyRules.remove(ordinaryRule);
log.error("新增上班时段处于原请假时段中间{}", JSON.toJSONString(ordinaryRule));
resultList.add(DailyRuleResultVo.successBuild(leaveRule, ordinaryRule));
return;
}
//新增上班时间完全覆盖原来请假时段
if (DateDetail.checkTimeBetween(leaveRule.getApplyStart(), ordinaryRule.getInPoint(), ordinaryRule.getOutPoint())
&& DateDetail.checkTimeBetween(leaveRule.getApplyEnd(), ordinaryRule.getInPoint(), ordinaryRule.getOutPoint())) {
leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
FtbAttendanceDailyRule rule1 = BeanUtil.toBean(ordinaryRule, FtbAttendanceDailyRule.class);
resultList.add(DailyRuleResultVo.successBuild(leaveRule, ordinaryRule));
ordinaryRule.setOutLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getOutLackPoint(), leaveRule.getApplyStart()));
ordinaryRule.setEarlyPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getEarlyPoint(), leaveRule.getApplyStart()));
ordinaryRule.setOutPoint(leaveRule.getApplyStart());
ordinaryRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), leaveRule.getApplyStart()));
ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), leaveRule.getApplyStart()));
getBreakTimeByOrdinary(leaveRule, ordinaryRule);
rule1.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), leaveRule.getApplyEnd()));
rule1.setClockStartPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getClockStartPoint(), leaveRule.getApplyEnd()));
rule1.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), leaveRule.getApplyEnd()));
rule1.setInPoint(leaveRule.getApplyEnd());
rule1.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
rule1.setId(RandomUtil.uuId());
getBreakTimeByOrdinary(leaveRule, rule1);
houseLeaveDayProcess(leaveRule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
if (!hisDailyRules.contains(ordinaryRule)) {
ordinaryRule.insertTrue();
hisDailyRules.add(ordinaryRule);
}
if (DateUtil.dateDiff(ordinaryRule.getOutPoint(), ordinaryRule.getInPoint()) == 0) {
hisDailyRules.remove(ordinaryRule);
}
log.error("新增上班时间完全覆盖原来请假时段{}", JSON.toJSONString(ordinaryRule));
if (DateUtil.dateDiff(rule1.getOutPoint(), rule1.getInPoint()) != 0) {
leaveRuleIterator.remove();
if (!leaveRuleIterator.hasNext()) {
if (!hisDailyRules.contains(rule1)) {
rule1.insertTrue();
hisDailyRules.add(rule1);
resultList.add(DailyRuleResultVo.successBuild(leaveRule, rule1));
}
return;
}
houseLeaveHandle(hisDailyRules, rule1, leaveRuleIterator, resultList);
}
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkTimeBetweenR(ordinaryRule.getOutPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())) {
leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
leaveRule.setOutPoint(ordinaryRule.getOutPoint());
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
ordinaryRule.setOutLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getOutLackPoint(), leaveRule.getApplyStart()));
ordinaryRule.setEarlyPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getEarlyPoint(), leaveRule.getApplyEnd()));
ordinaryRule.setOutPoint(leaveRule.getApplyStart());
ordinaryRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), ordinaryRule.getInPoint()));
ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), ordinaryRule.getInPoint()));
getBreakTimeByOrdinary(leaveRule, ordinaryRule);
houseLeaveDayProcess(leaveRule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
log.error("新增上班时段开始部分覆盖原请假时段中间{}", JSON.toJSONString(ordinaryRule));
if (!hisDailyRules.contains(ordinaryRule)) {
ordinaryRule.insertTrue();
hisDailyRules.add(ordinaryRule);
}
resultList.add(DailyRuleResultVo.successBuild(leaveRule, ordinaryRule));
return;
}
//结束部分覆盖
if (DateDetail.checkTimeBetweenL(ordinaryRule.getInPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())) {
leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
leaveRule.setInPoint(ordinaryRule.getInPoint());
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), leaveRule.getApplyEnd()));
ordinaryRule.setClockStartPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getClockStartPoint(), leaveRule.getApplyEnd()));
ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), leaveRule.getApplyEnd()));
ordinaryRule.setInPoint(leaveRule.getApplyEnd());
ordinaryRule.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
getBreakTimeByOrdinary(leaveRule, ordinaryRule);
houseLeaveDayProcess(leaveRule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
log.error("新增上班时段结束部分覆盖原请假时段中间{}", JSON.toJSONString(ordinaryRule));
if (DateUtil.dateDiff(ordinaryRule.getOutPoint(), ordinaryRule.getInPoint()) != 0) {
leaveRuleIterator.remove();
if (!leaveRuleIterator.hasNext()) {
if (!hisDailyRules.contains(ordinaryRule)) {
ordinaryRule.insertTrue();
hisDailyRules.add(ordinaryRule);
resultList.add(DailyRuleResultVo.successBuild(leaveRule, ordinaryRule));
}
return;
}
houseLeaveHandle(hisDailyRules, ordinaryRule, leaveRuleIterator, resultList);
}
return;
}
if (!leaveRule.getIsInsert()) {
leaveRule.setApplyViewEnable(2);
}
if (!hisDailyRules.contains(ordinaryRule) && !ordinaryRule.getIsInsert()) {
//完全没交集
hisDailyRules.add(ordinaryRule);
ordinaryRule.insertTrue();
}
log.error("新增上班时间与原来请假时段完全没交集{}", JSON.toJSONString(ordinaryRule));
}
private FtbAttendanceDailyRule getFtbAttendanceDailyRule(FtbAttendanceDailyRule ordinaryRule, FtbAttendanceDailyRule rule) {
if (rule.getIsInsert()) {
rule = BeanUtil.toBean(rule, FtbAttendanceDailyRule.class);
rule.setId(RandomUtil.uuId());
rule.setSelfGroup(ordinaryRule.getSelfGroup());
rule.setLeaveDay(BigDecimal.ZERO);
rule.setPayrollHours(BigDecimal.ZERO);
}
rule.setApplyViewEnable(1);
rule.setFixedMark(ordinaryRule.getFixedMark());
rule.setBreakEnable(ordinaryRule.getBreakEnable());
rule.setSchedulesType(ordinaryRule.getSchedulesType());
rule.setShiftId(ordinaryRule.getShiftId());
rule.setPeriodId(ordinaryRule.getPeriodId());
rule.setInPoint(rule.getApplyStart());
rule.setOutPoint(rule.getApplyEnd());
rule.insertTrue();
return rule;
}
private void houseLeaveDayProcess(FtbAttendanceDailyRule leaveRule, Integer validDuration, BigDecimal periodWorkDay, BigDecimal payrollHours) {
leaveRule.calValidDuration();
leaveRule.setLeaveDay(Objects.isNull(periodWorkDay) ? null : BigDecimal.valueOf(leaveRule.getValidDuration())
.divide(BigDecimal.valueOf(validDuration), 4, RoundingMode.HALF_UP)
.multiply(periodWorkDay).setScale(2, RoundingMode.HALF_UP));
housePayrollHoursProcess(leaveRule, payrollHours, validDuration);
}
private void housePayrollHoursProcess(FtbAttendanceDailyRule leaveRule, BigDecimal payrollHours, Integer validDuration) {
leaveRule.calValidDuration();
leaveRule.setPayrollHours(Objects.isNull(payrollHours) ? null : BigDecimal.valueOf(leaveRule.getValidDuration())
.divide(BigDecimal.valueOf(validDuration), 4, RoundingMode.HALF_UP)
.multiply(payrollHours).setScale(2, RoundingMode.HALF_UP));
}
/**
* 天、半天请假
*
* @param hisDailyRules
* @param leaveRule
* @param ordinaryRule
* @param resultList
*/
private void daysLeaveHandle(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule leaveRule, FtbAttendanceDailyRule ordinaryRule, List<DailyRuleResultVo> resultList) {
//同一请假申请保留一条请假记录
if (Objects.isNull(leaveRule.getApplyUnit()) || Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode())) {
return;
}
LeaveParam leaveParam = JsonUtil.getJsonToBean(leaveRule.getLeaveParam(), LeaveParam.class);
//是否为半天假
halfDayLeave(hisDailyRules, ordinaryRule, resultList, leaveRule, leaveParam);
//全天请假
dayLeave(hisDailyRules, ordinaryRule, resultList, leaveRule);
//休息时间处理
//如果开始时间处于休息时间中间,开始时间变更为休息时间的开始时间
if (Objects.nonNull(ordinaryRule.getBreakStartPoint()) && DateDetail.checkTimeBetween(leaveRule.getInPoint(), ordinaryRule.getOriginBreakStartPoint(), ordinaryRule.getOriginBreakEndPoint())) {
leaveRule.setInPoint(ordinaryRule.getOriginBreakStartPoint());
leaveRule.setBreakStartPoint(ordinaryRule.getOriginBreakStartPoint());
ordinaryRule.setOutPoint(ordinaryRule.getOriginBreakStartPoint());
ordinaryRule.setBreakStartPoint(null);
ordinaryRule.setBreakEndPoint(null);
log.error("新增请假开始时间调整为休息开始时间{}", JSON.toJSONString(ordinaryRule.getOriginBreakStartPoint()));
}
//如果结束时间处理休息时间中间,结束时间变更为休息时间的结束时间
if (Objects.nonNull(ordinaryRule.getBreakStartPoint()) && DateDetail.checkTimeBetween(leaveRule.getOutPoint(), ordinaryRule.getOriginBreakStartPoint(), ordinaryRule.getOriginBreakEndPoint())) {
leaveRule.setOutPoint(ordinaryRule.getOriginBreakEndPoint());
leaveRule.setBreakEndPoint(ordinaryRule.getOriginBreakEndPoint());
ordinaryRule.setInPoint(ordinaryRule.getOriginBreakEndPoint());
ordinaryRule.setBreakStartPoint(null);
ordinaryRule.setBreakEndPoint(null);
log.error("新增请假结束时间调整为休息结束时间{}", JSON.toJSONString(ordinaryRule.getOriginBreakEndPoint()));
}
}
/**
* 处理全天请假的逻辑
*
* @param hisDailyRules 历史每日规则列表
* @param ordinaryRule 原有的每日规则
* @param resultList 结果列表,用于存储处理结果
* @param leaveRule 请假的每日规则
*/
private void dayLeave(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule ordinaryRule, List<DailyRuleResultVo> resultList, FtbAttendanceDailyRule leaveRule) {
// 检查请假类型是否为全天
if (!Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.DAY.getCode())) {
return;
}
// 如果是插入操作,则直接返回
if (leaveRule.getIsInsert()) {
return;
}
//全天请假
leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
hisDailyRules.remove(ordinaryRule);
leaveRule.setInPoint(ordinaryRule.getInPoint());
leaveRule.setOutPoint(ordinaryRule.getOutPoint());
//如果为全天班,则请假时长为时段工时
leaveRule.setLeaveDay(!Objects.equals(ordinaryRule.getSchedulesType(), 0) ? ordinaryRule.getPeriodWorkDay() : BigDecimal.ONE);
leaveRule.setPayrollHours(ordinaryRule.getPayrollHours());
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
log.error("新增全天请假时间覆盖原来班时段{}", JSON.toJSONString(leaveRule));
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
}
private void halfDayLeave(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule ordinaryRule, List<DailyRuleResultVo> resultList, FtbAttendanceDailyRule leaveRule, LeaveParam leaveParam) {
//是否为半天假
if (!Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.HALF_DAY.getCode())) {
return;
}
//划线排班,隐藏半天请假
if (Objects.equals(ordinaryRule.getFixedMark(), 2)) {
leaveRule.setApplyViewEnable(0);
return;
}
if (isNotBetweenByHalfDayLeave(ordinaryRule, leaveParam)) {
//完全没交集
if (!hisDailyRules.contains(leaveRule)) {
leaveRule.setApplyViewEnable(2);
hisDailyRules.add(leaveRule);
}
if (!hisDailyRules.contains(ordinaryRule)) {
hisDailyRules.add(ordinaryRule);
}
return;
}
leaveRule = getFtbAttendanceDailyRule(ordinaryRule, leaveRule);
if (Objects.equals(ordinaryRule.getSchedulesType(), 0)) {
Date leaveDate = getLeaveDate(ordinaryRule);
boolean isMorningHalfDay = isHalfDayLeave(ordinaryRule, leaveParam, 1);
boolean isAfternoonHalfDay = isHalfDayLeave(ordinaryRule, leaveParam, 2);
//请假开始是否为上半天请假
if (isMorningHalfDay && !isAfternoonHalfDay) {
if (leaveDate.before(ordinaryRule.getInPoint())) {
return;
}
//请假开始时间为开始日期当天排班开始时间
leaveRule.setInPoint(ordinaryRule.getOriginInPoint());
leaveRule.setOutPoint(leaveDate);
leaveRule.setSchedulesType(ordinaryRule.getSchedulesType());
leaveRule.setLeaveDay(BigDecimal.valueOf(0.5));
getBreakTimeByOrdinary(leaveRule,ordinaryRule);
housePayrollHoursProcess(leaveRule, ordinaryRule.getPayrollHours(), ordinaryRule.getOriginValidDuration());
if (leaveDate.compareTo(ordinaryRule.getInPoint()) == 0) {
log.error("新增下半天请假时间覆盖原来全天班时段{}", JSON.toJSONString(leaveRule));
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
hisDailyRules.remove(ordinaryRule);
return;
}
ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), leaveDate));
ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), leaveDate));
ordinaryRule.setInPoint(leaveDate);
ordinaryRule.setSchedulesType(2);
ordinaryRule.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
housePayrollHoursProcess(ordinaryRule, ordinaryRule.getPayrollHours(), ordinaryRule.getOriginValidDuration());
log.error("新增全天班时段时间覆盖原来上半天请假{}", JSON.toJSONString(leaveRule));
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
if (!hisDailyRules.contains(ordinaryRule)) {
hisDailyRules.add(ordinaryRule);
}
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
//请假开始是否为下半天请假
} else if (!isMorningHalfDay && isAfternoonHalfDay) {
if (leaveDate.after(ordinaryRule.getOutPoint())) {
return;
}
leaveRule.setInPoint(leaveDate);
leaveRule.setSchedulesType(ordinaryRule.getSchedulesType());
leaveRule.setOutPoint(ordinaryRule.getOriginOutPoint());
leaveRule.setLeaveDay(BigDecimal.valueOf(0.5));
getBreakTimeByOrdinary(leaveRule,ordinaryRule);
housePayrollHoursProcess(leaveRule, ordinaryRule.getPayrollHours(), ordinaryRule.getOriginValidDuration());
if (leaveDate.compareTo(ordinaryRule.getInPoint()) == 0) {
log.error("新增下半天请假时间覆盖原来全天班时段{}", JSON.toJSONString(leaveRule));
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
hisDailyRules.remove(ordinaryRule);
return;
}
ordinaryRule.setEarlyPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getEarlyPoint(), leaveDate));
ordinaryRule.setOutLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getOutLackPoint(), leaveDate));
ordinaryRule.setOutPoint(leaveDate);
ordinaryRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
ordinaryRule.setSchedulesType(1);
housePayrollHoursProcess(ordinaryRule, ordinaryRule.getPayrollHours(), ordinaryRule.getOriginValidDuration());
log.error("新增全天班时段覆盖原来下半天请假时间{}", JSON.toJSONString(leaveRule));
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
if (!hisDailyRules.contains(ordinaryRule)) {
hisDailyRules.add(ordinaryRule);
}
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
} else {
//请假两个半天,隐藏全天班
leaveRule.setInPoint(ordinaryRule.getInPoint());
leaveRule.setOutPoint(ordinaryRule.getOutPoint());
leaveRule.setSchedulesType(ordinaryRule.getSchedulesType());
leaveRule.setLeaveDay(BigDecimal.ONE);
housePayrollHoursProcess(leaveRule, ordinaryRule.getPayrollHours(), ordinaryRule.getOriginValidDuration());
hisDailyRules.removeIf(rule -> StringUtil.equals(rule.getId(), ordinaryRule.getId()));
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
if (!hisDailyRules.contains(ordinaryRule)) {
ordinaryRule.setApplyViewEnable(0);
hisDailyRules.add(ordinaryRule);
}
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
log.error("新增全天班完全覆盖请假时间{}", JSON.toJSONString(ordinaryRule));
}
return;
}
//如果为半天班,每个上下班只保留一条
if (!Objects.equals(ordinaryRule.getSchedulesType(), leaveRule.getSchedulesType())) {
return;
}
//请假开始时间为开始日期当天排班开始时间
leaveRule.setInPoint(ordinaryRule.getInPoint());
leaveRule.setOutPoint(ordinaryRule.getOutPoint());
leaveRule.setSchedulesType(ordinaryRule.getSchedulesType());
leaveRule.setLeaveDay(BigDecimal.valueOf(0.5));
leaveRule.setPayrollHours(ordinaryRule.getPayrollHours());
getBreakTimeByOrdinary(leaveRule, ordinaryRule);
hisDailyRules.removeIf(rule -> StringUtil.equals(rule.getId(), ordinaryRule.getId()));
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
ordinaryRule.insertTrue();
log.error("新增半天班时段覆盖原来半天请假时间{}", JSON.toJSONString(leaveRule));
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, leaveRule));
}
// 提取辅助方法,减少重复逻辑
private boolean isHalfDayLeave(FtbAttendanceDailyRule oldRule, LeaveParam leaveParam, int timeType) {
// 开始日期且时间类型匹配
boolean isStartDateMatch = Objects.equals(leaveParam.getStartTimeType(), timeType) &&
oldRule.getDay().compareTo(leaveParam.getStart()) == 0;
// 中间日期
boolean isMiddleDate = (Objects.equals(timeType, 2) || oldRule.getDay().after(leaveParam.getStart())) &&
(Objects.equals(timeType, 1) || oldRule.getDay().before(leaveParam.getEnd()));
// 结束日期且时间类型匹配
boolean isEndDateMatch = Objects.equals(leaveParam.getEndTimeType(), timeType) &&
oldRule.getDay().compareTo(leaveParam.getEnd()) == 0;
return isStartDateMatch || isMiddleDate || isEndDateMatch;
}
/**
* 是否不属于半天、全天假范围内
*
* @param oldRule2
* @param leaveParam
* @return
*/
private static boolean isNotBetweenByHalfDayLeave(FtbAttendanceDailyRule oldRule2, LeaveParam leaveParam) {
return !DateDetail.checkTimeBetween(oldRule2.getDay(), leaveParam.getStart(), leaveParam.getEnd())
|| !Objects.equals(oldRule2.getSchedulesType(), 0) && leaveParam.getStartTimeType() > oldRule2.getSchedulesType() && oldRule2.getDay().compareTo(leaveParam.getStart()) == 0
|| !Objects.equals(oldRule2.getSchedulesType(), 0) && leaveParam.getEndTimeType() < oldRule2.getSchedulesType() && oldRule2.getDay().compareTo(leaveParam.getEnd()) == 0;
}
/**
* 计算半天请假全天班中间临界请假时间
*
* @param ftbAttendanceDailyRule
* @return
*/
private Date getLeaveDate(FtbAttendanceDailyRule ftbAttendanceDailyRule) {
int ruleMinute = DateDetail.calculateMinuteDiff(ftbAttendanceDailyRule.getOriginInPoint(), ftbAttendanceDailyRule.getOriginOutPoint());
return cn.hutool.core.date.DateUtil.offsetMinute(ftbAttendanceDailyRule.getOriginInPoint(), ruleMinute / 2);
}
/**
* 计算请假天数
*
* @param ordinaryRule
* @param leaveRule
*/
private void leaveDaysProcess(FtbAttendanceDailyRule ordinaryRule, FtbAttendanceDailyRule leaveRule) {
//查询是否为全天班
boolean isFullDay = Objects.equals(ordinaryRule.getSchedulesType(), 0);
//是否为半天请假
if (Objects.equals(leaveRule.getApplyUnit(), 3)) {
//如果为全天班且当天请假时长为多个半天则设置为1
if (isFullDay && leaveRule.getLeaveDay().compareTo(BigDecimal.valueOf(0.5)) > 0) {
leaveRule.setLeaveDay(BigDecimal.ONE);
leaveRule.setPayrollHours(ordinaryRule.getPayrollHours());
} else {
leaveRule.setLeaveDay(ordinaryRule.getPeriodWorkDay());
leaveRule.setPayrollHours(ordinaryRule.getPayrollHours());
}
}
//是否为全天请假
if (Objects.equals(leaveRule.getApplyUnit(), 2)) {
leaveRule.setLeaveDay(BigDecimal.ONE);
if (!isFullDay) {
//如果为半天班且班次数量大于1则设置为0.5
leaveRule.setLeaveDay(ordinaryRule.getPeriodWorkDay());
leaveRule.setPayrollHours(ordinaryRule.getPayrollHours());
}
}
}
/**
* 新增排班的休息时间处理
*
* @param leaveRule 原请假规则
* @param ordinaryRule 新增正常排班规则
*/
private void getBreakTimeByOrdinary(FtbAttendanceDailyRule leaveRule, FtbAttendanceDailyRule ordinaryRule) {
leaveRule.insertTrue();
if (!Objects.equals(ordinaryRule.getBreakEnable(), 1) || Objects.isNull(ordinaryRule.getBreakStartPoint())) {
return;
}
leaveRule.setBreakStartPoint(leaveRule.getInPoint().after(ordinaryRule.getBreakEndPoint())|| leaveRule.getOutPoint().before(ordinaryRule.getBreakStartPoint()) ? null : leaveRule.getInPoint().after(ordinaryRule.getBreakStartPoint()) ? leaveRule.getInPoint() : ordinaryRule.getBreakStartPoint());
leaveRule.setBreakEndPoint(leaveRule.getInPoint().after(ordinaryRule.getBreakEndPoint()) || leaveRule.getOutPoint().before(ordinaryRule.getBreakStartPoint()) ? null : leaveRule.getOutPoint().before(ordinaryRule.getBreakEndPoint()) ? leaveRule.getOutPoint() : ordinaryRule.getBreakEndPoint());
//休息结束时间小于排班上班时间,或者休息开始时间大于排班下班时间
if (ordinaryRule.getBreakEndPoint().compareTo(ordinaryRule.getInPoint()) <= 0 || ordinaryRule.getBreakStartPoint().compareTo(ordinaryRule.getOutPoint()) >= 0) {
ordinaryRule.setBreakStartPoint(null);
ordinaryRule.setBreakEndPoint(null);
ordinaryRule.setBreakEnable(0);
return;
}
//请假时间完全覆盖原来休息时段
if (DateDetail.checkTimeBetween(ordinaryRule.getBreakStartPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())
&& DateDetail.checkTimeBetween(ordinaryRule.getBreakEndPoint(), leaveRule.getApplyStart(), leaveRule.getApplyEnd())) {
ordinaryRule.setBreakStartPoint(null);
ordinaryRule.setBreakEndPoint(null);
ordinaryRule.setBreakEnable(0);
return;
}
//休息时间完全覆盖请假时间
if (DateDetail.checkTimeBetween(leaveRule.getApplyStart(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())
&& DateDetail.checkTimeBetween(leaveRule.getApplyEnd(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())) {
if (leaveRule.getApplyStart().compareTo(ordinaryRule.getBreakStartPoint()) >= 0) {
ordinaryRule.setBreakEndPoint(leaveRule.getApplyStart());
leaveRule.setBreakStartPoint(leaveRule.getApplyStart());
}
if (leaveRule.getApplyEnd().compareTo(ordinaryRule.getBreakEndPoint()) <= 0) {
leaveRule.setBreakEndPoint(leaveRule.getApplyEnd());
ordinaryRule.setBreakEndPoint(leaveRule.getApplyEnd());
}
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkTimeBetween(leaveRule.getApplyEnd(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())) {
leaveRule.setBreakEndPoint(leaveRule.getApplyEnd());
ordinaryRule.setBreakStartPoint(leaveRule.getApplyEnd());
return;
}
//结束部分覆盖
if (DateDetail.checkTimeBetween(leaveRule.getApplyStart(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())) {
ordinaryRule.setBreakEndPoint(leaveRule.getApplyStart());
leaveRule.setBreakStartPoint(leaveRule.getApplyStart());
return;
}
}
/**
* 新增排休
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean restHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增排休
if (!Objects.equals(AttendanceTypeEnum.REST.getCode(), rule.getAttendanceType())
&& !Objects.equals(AttendanceTypeEnum.DEDUCTION_HOLIDAYS.getCode(), rule.getAttendanceType())
&& !Objects.equals(AttendanceTypeEnum.EXCHANGE_HOLIDAYS.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//新加入数据不做处理
if (oldRule.getIsInsert()) {
return;
}
rule.setShiftId(oldRule.getShiftId());
rule.setPeriodId(oldRule.getPeriodId());
if (Objects.nonNull(rule.getOutPoint()) && (rule.getOutPoint().before(oldRule.getInPoint()) || oldRule.getInPoint().before(rule.getOutPoint()))) {
//完全没交集
rule.insertTrue();
hisDailyRules.add(rule);
log.error("新增排休与原来请假时段完全没交集{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
log.error(AttendanceConstant.getSchedulingResult(rule.getUserId(), rule.getDay(), AttendanceConstant.LEAVE, AttendanceTypeEnum.getMsg(rule.getAttendanceType())));
resultList.add(DailyRuleResultVo.build(rule, AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType(), oldRule.getFixedMark()));
});
return Boolean.TRUE;
}
/**
* 新增加班
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean workOvertimeHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增加班
if (!Objects.equals(AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//新加入数据不做处理
if (oldRule.getIsInsert()) {
return;
}
rule.setShiftId(oldRule.getShiftId());
rule.setPeriodId(oldRule.getPeriodId());
//完全覆盖
//加班时间完全覆盖原来请假时段
if (DateDetail.checkTimeBetween(oldRule.getInPoint(), rule.getInPoint(), rule.getOutPoint())
&& DateDetail.checkTimeBetween(oldRule.getOutPoint(), rule.getInPoint(), rule.getOutPoint())) {
oldRule.setInPoint(oldRule.getApplyStart());
oldRule.setOutPoint(oldRule.getApplyEnd());
oldRule.setApplyViewEnable(0);
if (!hisDailyRules.contains(rule)) {
rule.insertTrue();
hisDailyRules.add(rule);
}
log.error("新增加班时间完全覆盖原来请假时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkTimeBetweenR(rule.getOutPoint(), oldRule.getInPoint(), oldRule.getOutPoint())) {
oldRule.setInPoint(rule.getApplyEnd());
oldRule.setApplyViewEnable(1);
if (!hisDailyRules.contains(rule)) {
rule.insertTrue();
hisDailyRules.add(rule);
}
log.error("新增加班时间完全开始部分覆盖原来请假时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//结束部分覆盖
if (DateDetail.checkTimeBetweenL(rule.getInPoint(), oldRule.getInPoint(), oldRule.getOutPoint())) {
oldRule.setOutPoint(rule.getApplyStart());
rule.setApplyViewEnable(1);
if (!hisDailyRules.contains(rule)) {
rule.insertTrue();
hisDailyRules.add(rule);
}
log.error("新增加班时间完全结束部分覆盖原来请假时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//请假完全覆盖加班
if (DateDetail.checkTimeBetween(rule.getInPoint(), oldRule.getInPoint(), oldRule.getOutPoint())
&& DateDetail.checkTimeBetween(rule.getOutPoint(), oldRule.getInPoint(), oldRule.getOutPoint())) {
FtbAttendanceDailyRule oldRule1 = BeanUtil.toBean(oldRule, FtbAttendanceDailyRule.class);
oldRule.setOutPoint(rule.getApplyStart());
oldRule1.setInPoint(rule.getApplyEnd());
oldRule1.setId(RandomUtil.uuId());
oldRule1.setApplyViewEnable(1);
oldRule1.insertTrue();
hisDailyRules.add(oldRule1);
if (!hisDailyRules.contains(rule)) {
rule.insertTrue();
hisDailyRules.add(rule);
}
log.error("原来请假时段完全覆盖新增加班时间{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//完全没交集
if (!hisDailyRules.contains(rule)) {
rule.insertTrue();
hisDailyRules.add(rule);
}
log.error("新增加班时间与原来请假时段完全没交集{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
});
return Boolean.TRUE;
}
}

View File

@@ -0,0 +1,737 @@
package jnpf.attendance.service.handle.rule;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import jnpf.attendance.service.RuleProcessor;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.entity.attendance.LeaveParam;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.LeaveUnitEnum;
import jnpf.enums.attendance.v2.WorkBoundaryCoverageEnum;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import jnpf.util.DateDetail;
import jnpf.util.DateUtil;
import jnpf.util.JsonUtil;
import jnpf.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
/**
* 处理历史普通排班
*/
@Component
@Slf4j
public class OrdinaryRuleProcessor extends RuleProcessor {
@Override
public void ruleArrangementHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> currDailyRule, List<DailyRuleResultVo> resultList) {
Map<Integer, List<FtbAttendanceDailyRule>> collect = hisDailyRules.stream().collect(Collectors.groupingBy(FtbAttendanceDailyRule::getAttendanceType));
List<FtbAttendanceDailyRule> ftbAttendanceDailyRules = collect.get(AttendanceTypeEnum.ORDINARY.getCode());
if (CollUtil.isNotEmpty(ftbAttendanceDailyRules)) {
Iterator<FtbAttendanceDailyRule> iterator = currDailyRule.iterator();
while (iterator.hasNext()) {
FtbAttendanceDailyRule rule = iterator.next();
//新增排休
if (restHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增上班
if (ordinaryHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增加班
if (workOvertimeHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增请假
if (leaveHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增外出、出差
if (stepOutHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增清除
clearHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList);
}
}
if (Objects.nonNull(nextRuleProcessor)) {
nextRuleProcessor.ruleArrangementHandle(hisDailyRules, currDailyRule, resultList);
}
}
/**
* 新增外出、出差申请
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean stepOutHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增外出
if (!Objects.equals(AttendanceTypeEnum.BUSINESS_TRIP.getCode(), rule.getAttendanceType()) && !Objects.equals(AttendanceTypeEnum.STEP_OUT.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//新加入数据不做处理
rule.setShiftId(oldRule.getShiftId());
rule.setPeriodId(oldRule.getPeriodId());
//原小时外出没命中已有班次数据,隐藏外出申请
if (rule.getOutPoint().before(oldRule.getInPoint())
|| rule.getInPoint().after(oldRule.getOutPoint())
|| rule.getInPoint().after(oldRule.getInPoint()) && rule.getOutPoint().before(oldRule.getOutPoint())) {
if (!rule.getIsInsert()) {
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
}
log.error("新增排班数据未命中小时外出申请或者外出数据完全被排班数据覆盖,过滤{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successNailBuild(rule));
return;
}
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
rule.setApplyViewEnable(0);
oldRule.setApplyViewEnable(rule.getAttendanceType());
//原小时外出数据覆盖现在新增排班数据上班时间
if (!rule.getInPoint().after(oldRule.getInPoint())) {
oldRule.setInStepOutType(1);
oldRule.setInStepOutApplyId(rule.getApplyId());
}
//原小时外出数据覆盖现在新增排班数据下班时间
if (!rule.getOutPoint().before(oldRule.getOutPoint())) {
oldRule.setOutStepOutType(1);
oldRule.setOutStepOutApplyId(rule.getApplyId());
}
log.error("新增外出、出差申请标记原普班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
});
return Boolean.TRUE;
}
/**
* 新增清除
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean clearHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增清除
if (!Objects.equals(AttendanceTypeEnum.CLEAR.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
hisDailyRules.removeAll(ftbAttendanceDailyRules);
ftbAttendanceDailyRules.forEach(oldRule -> resultList.add(DailyRuleResultVo.successBuild(oldRule)));
return Boolean.TRUE;
}
/**
* 新增请假
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule1 当前规则
*/
private Boolean leaveHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule1, List<DailyRuleResultVo> resultList) {
//新增请假
if (!Objects.equals(AttendanceTypeEnum.LEAVE.getCode(), rule1.getAttendanceType())) {
return Boolean.FALSE;
}
boolean isMultipleRules = ftbAttendanceDailyRules.size() > 1;
ftbAttendanceDailyRules.forEach(oldRule -> {
daysLeaveHandle(hisDailyRules, oldRule, rule1, resultList, isMultipleRules);
houseLeaveHandle(hisDailyRules, oldRule, rule1, resultList);
});
return Boolean.TRUE;
}
/**
* 小时请假
*
* @param hisDailyRules
* @param ordinaryRule
* @param rule
* @param resultList
*/
private void houseLeaveHandle(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule ordinaryRule, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
if (Objects.nonNull(rule.getApplyUnit()) && !Objects.equals(rule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode())) {
return;
}
//新加入数据不做处理
if (ordinaryRule.getIsInsert()) {
return;
}
//请假处于排班时段中间a
if (DateDetail.checkTimeBetween(rule.getApplyStart(), ordinaryRule.getInPoint(), ordinaryRule.getOutPoint())
&& DateDetail.checkTimeBetween(rule.getApplyEnd(), ordinaryRule.getInPoint(), ordinaryRule.getOutPoint())) {
FtbAttendanceDailyRule oldRule1 = BeanUtil.toBean(ordinaryRule, FtbAttendanceDailyRule.class);
rule = getFtbAttendanceDailyRule(ordinaryRule, rule);
ordinaryRule.setEarlyPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getEarlyPoint(), rule.getApplyStart()));
ordinaryRule.setOutLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getOutLackPoint(), rule.getApplyStart()));
ordinaryRule.setOutPoint(rule.getApplyStart());
ordinaryRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), ordinaryRule.getInPoint()));
ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), ordinaryRule.getInPoint()));
getBreakTimeByOrdinary(ordinaryRule, rule);
oldRule1.setClockStartPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getClockStartPoint(), rule.getApplyEnd()));
oldRule1.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), rule.getApplyEnd()));
oldRule1.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), rule.getApplyEnd()));
oldRule1.setInPoint(rule.getApplyEnd());
oldRule1.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
oldRule1.setId(RandomUtil.uuId());
getBreakTimeByOrdinary(oldRule1, rule);
houseLeaveDayProcess(rule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
oldRule1.insertTrue();
if (DateUtil.dateDiff(oldRule1.getOutPoint(), oldRule1.getInPoint()) != 0) {
hisDailyRules.add(oldRule1);
}
if (DateUtil.dateDiff(ordinaryRule.getOutPoint(), ordinaryRule.getInPoint()) == 0) {
hisDailyRules.remove(ordinaryRule);
}
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
log.error("新增请假处于排班时段中间{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, rule));
return;
}
//请假时间完全覆盖原来上班时段
if (DateDetail.checkTimeBetween(ordinaryRule.getInPoint(), rule.getApplyStart(), rule.getApplyEnd())
&& DateDetail.checkTimeBetween(ordinaryRule.getOutPoint(), rule.getApplyStart(), rule.getApplyEnd())) {
rule = getFtbAttendanceDailyRule(ordinaryRule, rule);
hisDailyRules.remove(ordinaryRule);
rule.setInPoint(ordinaryRule.getInPoint());
rule.setOutPoint(ordinaryRule.getOutPoint());
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
getBreakTimeByOrdinary(ordinaryRule, rule);
houseLeaveDayProcess(rule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
log.error("新增请假时间完全覆盖原来上班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, rule));
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkTimeBetweenR(rule.getApplyEnd(), ordinaryRule.getInPoint(), ordinaryRule.getOutPoint())) {
rule = getFtbAttendanceDailyRule(ordinaryRule, rule);
rule.setInPoint(ordinaryRule.getInPoint());
ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), rule.getApplyEnd()));
ordinaryRule.setClockStartPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getClockStartPoint(), rule.getApplyEnd()));
ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), rule.getApplyEnd()));
ordinaryRule.setInPoint(rule.getApplyEnd());
ordinaryRule.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
rule.insertTrue();
}
getBreakTimeByOrdinary(ordinaryRule, rule);
houseLeaveDayProcess(rule, ordinaryRule);
log.error("新增请假时间开始部分覆盖原来上班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, rule));
return;
}
//结束部分覆盖
if (DateDetail.checkTimeBetweenL(rule.getApplyStart(), ordinaryRule.getInPoint(), ordinaryRule.getOutPoint())) {
rule = getFtbAttendanceDailyRule(ordinaryRule, rule);
rule.setOutPoint(ordinaryRule.getOutPoint());
ordinaryRule.setEarlyPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getEarlyPoint(), rule.getApplyStart()));
ordinaryRule.setOutLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getOutPoint(), ordinaryRule.getOutLackPoint(), rule.getApplyStart()));
ordinaryRule.setOutPoint(rule.getApplyStart());
ordinaryRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
ordinaryRule.calInLackPoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getInLackPoint(), ordinaryRule.getInPoint()));
ordinaryRule.calLatePoint(DateDetail.getNewDateByPeriod(ordinaryRule.getInPoint(), ordinaryRule.getLatePoint(), ordinaryRule.getInPoint()));
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
rule.insertTrue();
}
getBreakTimeByOrdinary(ordinaryRule, rule);
houseLeaveDayProcess(rule, ordinaryRule);
log.error("新增请假时间结束部分覆盖原来上班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(ordinaryRule, rule));
return;
}
//完全没交集
if (!hisDailyRules.contains(rule) && !rule.getIsInsert()) {
rule.setShiftId(ordinaryRule.getShiftId());
rule.setPeriodId(ordinaryRule.getPeriodId());
rule.setApplyViewEnable(2);
hisDailyRules.add(rule);
log.error("新增请假与原排班时段中间没交集{}", JSON.toJSONString(rule));
}
}
private FtbAttendanceDailyRule getFtbAttendanceDailyRule(FtbAttendanceDailyRule ordinaryRule, FtbAttendanceDailyRule rule) {
if (rule.getIsInsert()) {
rule = BeanUtil.toBean(rule, FtbAttendanceDailyRule.class);
rule.setId(RandomUtil.uuId());
rule.setSelfGroup(ordinaryRule.getSelfGroup());
}
rule.setApplyViewEnable(1);
rule.setFixedMark(ordinaryRule.getFixedMark());
rule.setBreakEnable(ordinaryRule.getBreakEnable());
rule.setSchedulesType(ordinaryRule.getSchedulesType());
rule.setShiftId(ordinaryRule.getShiftId());
rule.setPeriodId(ordinaryRule.getPeriodId());
rule.setInPoint(rule.getApplyStart());
rule.setOutPoint(rule.getApplyEnd());
rule.setOriginInPoint(ordinaryRule.getOriginInPoint());
rule.setOriginOutPoint(ordinaryRule.getOriginOutPoint());
rule.insertTrue();
return rule;
}
/**
* 天、半天请假
*
* @param hisDailyRules
* @param oldRule
* @param leaveRule
* @param resultList
*/
private void daysLeaveHandle(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule oldRule, FtbAttendanceDailyRule leaveRule, List<DailyRuleResultVo> resultList, Boolean isMultipleRules) {
if (Objects.isNull(leaveRule.getApplyUnit()) || Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.HOUR.getCode())) {
return;
}
LeaveParam leaveParam = JsonUtil.getJsonToBean(leaveRule.getLeaveParam(), LeaveParam.class);
//是否为半天假
//开始日期
//是否为全天班
halfDayLeave(hisDailyRules, oldRule, resultList, leaveRule, leaveParam);
//全天请假
dayLeave(hisDailyRules, oldRule, resultList, leaveRule);
//休息时间处理
//如果开始时间处于休息时间中间,开始时间变更为休息时间的开始时间
if (Objects.nonNull(oldRule.getBreakStartPoint()) && DateDetail.checkTimeBetween(leaveRule.getInPoint(), oldRule.getOriginBreakStartPoint(), oldRule.getOriginBreakEndPoint())) {
leaveRule.setInPoint(oldRule.getOriginBreakStartPoint());
leaveRule.setBreakStartPoint(oldRule.getOriginBreakStartPoint());
oldRule.setOutPoint(oldRule.getOriginBreakStartPoint());
oldRule.setBreakStartPoint(null);
oldRule.setBreakEndPoint(null);
log.error("新增请假开始时间调整为休息开始时间{}", JSON.toJSONString(oldRule.getOriginBreakStartPoint()));
}
//如果结束时间处理休息时间中间,结束时间变更为休息时间的结束时间
if (Objects.nonNull(oldRule.getBreakStartPoint()) && DateDetail.checkTimeBetween(leaveRule.getOutPoint(), oldRule.getOriginBreakStartPoint(), oldRule.getOriginBreakEndPoint())) {
leaveRule.setOutPoint(oldRule.getOriginBreakEndPoint());
leaveRule.setBreakEndPoint(oldRule.getOriginBreakEndPoint());
oldRule.setInPoint(oldRule.getOriginBreakEndPoint());
oldRule.setBreakStartPoint(null);
oldRule.setBreakEndPoint(null);
log.error("新增请假结束时间调整为休息结束时间{}", JSON.toJSONString(oldRule.getOriginBreakEndPoint()));
}
}
private void dayLeave(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule oldRule, List<DailyRuleResultVo> resultList, FtbAttendanceDailyRule leaveRule) {
if (!Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.DAY.getCode())) {
return;
}
//全天请假
leaveRule = getFtbAttendanceDailyRule(oldRule, leaveRule);
hisDailyRules.remove(oldRule);
leaveRule.setInPoint(oldRule.getInPoint());
leaveRule.setOutPoint(oldRule.getOutPoint());
//如果为全天班,则请假时长为时段工时
leaveRule.setLeaveDay(!Objects.equals(oldRule.getSchedulesType(), 0) ? oldRule.getPeriodWorkDay() : BigDecimal.ONE);
leaveRule.setPayrollHours(oldRule.getPayrollHours());
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
log.error("新增全天请假时间覆盖原来班时段{}", JSON.toJSONString(leaveRule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, leaveRule));
}
private void halfDayLeave(List<FtbAttendanceDailyRule> hisDailyRules, FtbAttendanceDailyRule oldRule, List<DailyRuleResultVo> resultList, FtbAttendanceDailyRule leaveRule, LeaveParam leaveParam) {
//是否为半天假
if (!Objects.equals(leaveRule.getApplyUnit(), LeaveUnitEnum.HALF_DAY.getCode())) {
return;
}
//划线排班,隐藏半天请假
if (Objects.equals(oldRule.getFixedMark(), 2)) {
log.error("划线排班,隐藏半天请假{}", JSON.toJSONString(oldRule));
leaveRule.setApplyViewEnable(0);
return;
}
if (isNotBetweenByHalfDayLeave(oldRule, leaveParam, leaveRule)) {
//完全没交集
if (!hisDailyRules.contains(leaveRule)) {
leaveRule.setApplyViewEnable(2);
leaveRule.setFixedMark(oldRule.getFixedMark());
hisDailyRules.add(leaveRule);
}
return;
}
leaveRule = getFtbAttendanceDailyRule(oldRule, leaveRule);
if (Objects.equals(oldRule.getSchedulesType(), 0)) {
Date leaveDate = getLeaveDate(oldRule);
boolean isMorningHalfDay = isHalfDayLeave(oldRule, leaveParam, 1);
boolean isAfternoonHalfDay = isHalfDayLeave(oldRule, leaveParam, 2);
//请假开始是否为上半天请假
if (isMorningHalfDay && !isAfternoonHalfDay) {
if (leaveDate.before(oldRule.getInPoint())) {
return;
}
//请假开始时间为开始日期当天排班开始时间
leaveRule.setInPoint(oldRule.getOriginInPoint());
leaveRule.setOutPoint(leaveDate);
leaveRule.setSchedulesType(oldRule.getSchedulesType());
leaveRule.setLeaveDay(BigDecimal.valueOf(0.5));
leaveRule.setSchedulesType(1);
leaveRule.insertTrue();
getBreakTimeByOrdinary(oldRule, leaveRule);
housePayrollHoursProcess(leaveRule, oldRule.getPayrollHours(),oldRule.getOriginValidDuration());
if (leaveDate.compareTo(oldRule.getOutPoint()) == 0) {
log.error("新增下半天请假时间覆盖原来全天班时段{}", JSON.toJSONString(leaveRule));
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
resultList.add(DailyRuleResultVo.successBuild(oldRule, leaveRule));
hisDailyRules.remove(oldRule);
return;
}
oldRule.calInLackPoint(DateDetail.getNewDateByPeriod(oldRule.getInPoint(), oldRule.getInLackPoint(), leaveDate));
oldRule.calLatePoint(DateDetail.getNewDateByPeriod(oldRule.getInPoint(), oldRule.getLatePoint(), leaveDate));
oldRule.setInPoint(leaveDate);
oldRule.setInUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
oldRule.setSchedulesType(2);
housePayrollHoursProcess(oldRule, oldRule.getPayrollHours(), oldRule.getOriginValidDuration());
log.error("新增上半天请假时间覆盖原来全天班时段{}", JSON.toJSONString(leaveRule));
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
resultList.add(DailyRuleResultVo.successBuild(oldRule, leaveRule));
} else if (!isMorningHalfDay && isAfternoonHalfDay) {
if (leaveDate.after(oldRule.getOutPoint())) {
return;
}
leaveRule.setInPoint(leaveDate);
leaveRule.setSchedulesType(oldRule.getSchedulesType());
leaveRule.setOutPoint(oldRule.getOriginOutPoint());
leaveRule.setLeaveDay(BigDecimal.valueOf(0.5));
leaveRule.setSchedulesType(2);
leaveRule.insertTrue();
getBreakTimeByOrdinary(oldRule, leaveRule);
housePayrollHoursProcess(leaveRule, oldRule.getPayrollHours(), oldRule.getOriginValidDuration());
if (leaveDate.compareTo(oldRule.getInPoint()) == 0) {
log.error("新增下半天请假时间覆盖原来全天班时段{}", JSON.toJSONString(leaveRule));
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
resultList.add(DailyRuleResultVo.successBuild(oldRule, leaveRule));
hisDailyRules.remove(oldRule);
return;
}
oldRule.setEarlyPoint(DateDetail.getNewDateByPeriod(oldRule.getOutPoint(), oldRule.getEarlyPoint(), leaveDate));
oldRule.setOutLackPoint(DateDetail.getNewDateByPeriod(oldRule.getOutPoint(), oldRule.getOutLackPoint(), leaveDate));
oldRule.setOutPoint(leaveDate);
oldRule.setOutUnbounded(WorkBoundaryCoverageEnum.LEAVE_COVERED.getCode());
oldRule.setSchedulesType(1);
housePayrollHoursProcess(oldRule, oldRule.getPayrollHours(), oldRule.getOriginValidDuration());
log.error("新增下半天请假时间覆盖原来全天班时段{}", JSON.toJSONString(leaveRule));
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
resultList.add(DailyRuleResultVo.successBuild(oldRule, leaveRule));
} else {
leaveRule.setInPoint(oldRule.getInPoint());
leaveRule.setOutPoint(oldRule.getOutPoint());
leaveRule.setSchedulesType(oldRule.getSchedulesType());
getBreakTimeByOrdinary(oldRule, leaveRule);
houseLeaveDayProcess(leaveRule, oldRule);
leaveRule.insertTrue();
hisDailyRules.remove(oldRule);
if (!hisDailyRules.contains(leaveRule)) {
hisDailyRules.add(leaveRule);
}
getBreakTimeByOrdinary(oldRule, leaveRule);
resultList.add(DailyRuleResultVo.successBuild(oldRule, leaveRule));
log.error("新增请假时间完全覆盖全天班{}", JSON.toJSONString(oldRule));
}
return;
}
//是否为半天班
if (!leaveRule.getSchedulesType().equals(oldRule.getSchedulesType())) {
return;
}
//请假开始时间为开始日期当天排班开始时间
leaveRule.setInPoint(oldRule.getInPoint());
leaveRule.setOutPoint(oldRule.getOutPoint());
leaveRule.setSchedulesType(oldRule.getSchedulesType());
if (!hisDailyRules.contains(leaveRule)) {
leaveRule.insertTrue();
hisDailyRules.add(leaveRule);
}
getBreakTimeByOrdinary(oldRule, leaveRule);
leaveRule.setLeaveDay(BigDecimal.valueOf(0.5));
leaveRule.setPayrollHours(oldRule.getPayrollHours());
hisDailyRules.remove(oldRule);
log.error("新增半天请假时间覆盖原来半天班时段{}", JSON.toJSONString(leaveRule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, leaveRule));
}
// 提取辅助方法,减少重复逻辑
private boolean isHalfDayLeave(FtbAttendanceDailyRule oldRule, LeaveParam leaveParam, int timeType) {
// 开始日期且时间类型匹配
boolean isStartDateMatch = Objects.equals(leaveParam.getStartTimeType(), timeType) &&
oldRule.getDay().compareTo(leaveParam.getStart()) == 0;
// 中间日期
boolean isMiddleDate = (Objects.equals(timeType, 2) || oldRule.getDay().after(leaveParam.getStart())) &&
(Objects.equals(timeType, 1) || oldRule.getDay().before(leaveParam.getEnd()));
// 结束日期且时间类型匹配
boolean isEndDateMatch = Objects.equals(leaveParam.getEndTimeType(), timeType) &&
oldRule.getDay().compareTo(leaveParam.getEnd()) == 0;
return isStartDateMatch || isMiddleDate || isEndDateMatch;
}
/**
* 半天请假是否班次未命中请假
*
* @param oldRule2
* @param leaveParam
* @param leaveRule
* @return
*/
private static boolean isNotBetweenByHalfDayLeave(FtbAttendanceDailyRule oldRule2, LeaveParam leaveParam, FtbAttendanceDailyRule leaveRule) {
return !DateDetail.checkTimeBetween(oldRule2.getDay(), leaveParam.getStart(), leaveParam.getEnd())
|| !Objects.equals(oldRule2.getSchedulesType(), 0) && leaveParam.getStartTimeType() > oldRule2.getSchedulesType() && oldRule2.getDay().compareTo(leaveParam.getStart()) == 0
|| !Objects.equals(oldRule2.getSchedulesType(), 0) && leaveParam.getEndTimeType() < oldRule2.getSchedulesType() && oldRule2.getDay().compareTo(leaveParam.getEnd()) == 0;
}
/**
* 计算半天请假全天班中间临界请假时间
*
* @param ftbAttendanceDailyRule
* @return
*/
private Date getLeaveDate(FtbAttendanceDailyRule ftbAttendanceDailyRule) {
int ruleMinute = DateDetail.calculateMinuteDiff(ftbAttendanceDailyRule.getOriginInPoint(), ftbAttendanceDailyRule.getOriginOutPoint());
Date dateTime = cn.hutool.core.date.DateUtil.offsetMinute(ftbAttendanceDailyRule.getOriginInPoint(), ruleMinute / 2);
return dateTime;
}
/**
* 新增请假的休息时间处理
*
* @param leaveRule 原请假规则
* @param ordinaryRule 新增正常排班规则
*/
private void getBreakTimeByOrdinary(FtbAttendanceDailyRule ordinaryRule, FtbAttendanceDailyRule leaveRule) {
if (!Objects.equals(ordinaryRule.getBreakEnable(), 1) || Objects.isNull(ordinaryRule.getBreakStartPoint())) {
return;
}
leaveRule.setBreakStartPoint(leaveRule.getInPoint().after(ordinaryRule.getBreakEndPoint())|| leaveRule.getOutPoint().before(ordinaryRule.getBreakStartPoint()) ? null : leaveRule.getInPoint().after(ordinaryRule.getBreakStartPoint()) ? leaveRule.getInPoint() : ordinaryRule.getBreakStartPoint());
leaveRule.setBreakEndPoint(leaveRule.getInPoint().after(ordinaryRule.getBreakEndPoint()) || leaveRule.getOutPoint().before(ordinaryRule.getBreakStartPoint()) ? null : leaveRule.getOutPoint().before(ordinaryRule.getBreakEndPoint()) ? leaveRule.getOutPoint() : ordinaryRule.getBreakEndPoint());
//休息结束时间小于排班上班时间,或者休息开始时间大于排班下班时间
if (ordinaryRule.getBreakEndPoint().compareTo(ordinaryRule.getInPoint()) <= 0 || ordinaryRule.getBreakStartPoint().compareTo(ordinaryRule.getOutPoint()) >= 0) {
ordinaryRule.setBreakStartPoint(null);
ordinaryRule.setBreakEndPoint(null);
ordinaryRule.setBreakEnable(0);
return;
}
//请假时间完全覆盖原来休息时段
if (DateDetail.checkTimeBetween(ordinaryRule.getBreakStartPoint(), leaveRule.getInPoint(), leaveRule.getOutPoint())
&& DateDetail.checkTimeBetween(ordinaryRule.getBreakEndPoint(), leaveRule.getInPoint(), leaveRule.getOutPoint())) {
ordinaryRule.setBreakStartPoint(null);
ordinaryRule.setBreakEndPoint(null);
ordinaryRule.setBreakEnable(0);
return;
}
//休息时间完全覆盖请假时间
if (DateDetail.checkTimeBetween(leaveRule.getInPoint(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())
&& DateDetail.checkTimeBetween(leaveRule.getOutPoint(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())) {
if (leaveRule.getInPoint().compareTo(ordinaryRule.getBreakStartPoint()) >= 0) {
ordinaryRule.setBreakEndPoint(leaveRule.getInPoint());
leaveRule.setBreakStartPoint(leaveRule.getInPoint());
}
if (leaveRule.getOutPoint().compareTo(ordinaryRule.getBreakEndPoint()) <= 0) {
leaveRule.setBreakEndPoint(leaveRule.getOutPoint());
ordinaryRule.setBreakEndPoint(leaveRule.getOutPoint());
}
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkTimeBetween(leaveRule.getOutPoint(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())) {
leaveRule.setBreakEndPoint(leaveRule.getOutPoint());
ordinaryRule.setBreakStartPoint(leaveRule.getOutPoint());
return;
}
//结束部分覆盖
if (DateDetail.checkTimeBetween(leaveRule.getInPoint(), ordinaryRule.getBreakStartPoint(), ordinaryRule.getBreakEndPoint())) {
ordinaryRule.setBreakEndPoint(leaveRule.getInPoint());
leaveRule.setBreakStartPoint(leaveRule.getInPoint());
}
}
private void houseLeaveDayProcess(FtbAttendanceDailyRule leaveRule, FtbAttendanceDailyRule ordinaryRule) {
houseLeaveDayProcess(leaveRule, ordinaryRule.getOriginValidDuration(), ordinaryRule.getPeriodWorkDay(), ordinaryRule.getPayrollHours());
}
private void houseLeaveDayProcess(FtbAttendanceDailyRule leaveRule, Integer validDuration, BigDecimal periodWorkDay, BigDecimal payrollHours) {
leaveRule.calValidDuration();
leaveRule.setLeaveDay(Objects.isNull(periodWorkDay) ? null : BigDecimal.valueOf(leaveRule.getValidDuration())
.divide(BigDecimal.valueOf(validDuration), 4, RoundingMode.HALF_UP)
.multiply(periodWorkDay).setScale(2, RoundingMode.HALF_UP));
housePayrollHoursProcess(leaveRule, payrollHours, validDuration);
}
private void housePayrollHoursProcess(FtbAttendanceDailyRule leaveRule, BigDecimal payrollHours, Integer validDuration) {
leaveRule.calValidDuration();
leaveRule.setPayrollHours(Objects.isNull(payrollHours) ? null : BigDecimal.valueOf(leaveRule.getValidDuration())
.divide(BigDecimal.valueOf(validDuration), 4, RoundingMode.HALF_UP)
.multiply(payrollHours).setScale(2, RoundingMode.HALF_UP));
}
/**
* 新增上班
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean ordinaryHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增上班
if (!Objects.equals(AttendanceTypeEnum.ORDINARY.getCode(), rule.getAttendanceType()) || rule.getIsInsert()) {
return Boolean.FALSE;
}
if (hisDailyRules.containsAll(ftbAttendanceDailyRules)) {
if (Objects.equals(rule.getFixedMark(), 1)) {
ftbAttendanceDailyRules = ftbAttendanceDailyRules.stream().filter(rule1 -> !Objects.equals(rule1.getFixedMark(), 3)).collect(Collectors.toList());
}
hisDailyRules.removeAll(ftbAttendanceDailyRules);
}
if (CollUtil.isNotEmpty(ftbAttendanceDailyRules)) {
if (!hisDailyRules.contains(rule)) {
if(ftbAttendanceDailyRules.stream().anyMatch(vo->Objects.equals(vo.getApplyViewEnable(),3))){
rule.setApplyViewEnable(3);
}
hisDailyRules.add(rule);
}
}
ftbAttendanceDailyRules.forEach(oldRule -> {
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
});
return Boolean.TRUE;
}
/**
* 新增排休
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean restHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增排休
if (!Objects.equals(AttendanceTypeEnum.REST.getCode(), rule.getAttendanceType())
&& !Objects.equals(AttendanceTypeEnum.HOLIDAYS.getCode(), rule.getAttendanceType())
&& !Objects.equals(AttendanceTypeEnum.DEDUCTION_HOLIDAYS.getCode(), rule.getAttendanceType())
&& !Objects.equals(AttendanceTypeEnum.EXCHANGE_HOLIDAYS.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
if (Objects.equals(rule.getFixedMark(), 1)) {
ftbAttendanceDailyRules = ftbAttendanceDailyRules.stream().filter(rule1 -> !Objects.equals(rule1.getFixedMark(), 3)).collect(Collectors.toList());
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//新加入数据不做处理
if (oldRule.getIsInsert()) {
return;
}
hisDailyRules.remove(oldRule);
});
if (CollUtil.isNotEmpty(ftbAttendanceDailyRules)) {
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
}
log.error("新增排休覆盖原来上班时段{},目标结果为{}", JSON.toJSONString(rule), JSON.toJSONString(hisDailyRules));
ftbAttendanceDailyRules.forEach(oldRule -> {
resultList.add(DailyRuleResultVo.successRestBuild(oldRule, rule, rule.getPeriodWorkDay()));
});
return Boolean.TRUE;
}
/**
* 新增加班
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean workOvertimeHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增加班
if (!Objects.equals(AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//新加入数据不做处理
if (oldRule.getIsInsert()) {
return;
}
rule.setSelfGroup(oldRule.getSelfGroup());
rule.setFixedMark(oldRule.getFixedMark());
//完全覆盖
if (DateDetail.checkTimeBetween(rule.getApplyStart(), oldRule.getInPoint(), oldRule.getOutPoint())
&& DateDetail.checkTimeBetween(rule.getApplyEnd(), oldRule.getInPoint(), oldRule.getOutPoint())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.ORDINARY));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.ORDINARY.getCode(), AttendanceTypeEnum.WORKOVERTIME.getCode()));
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkTimeBetweenR(rule.getApplyEnd(), oldRule.getInPoint(), oldRule.getOutPoint())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.ORDINARY));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.ORDINARY.getCode(), AttendanceTypeEnum.WORKOVERTIME.getCode()));
return;
}
//结束部分覆盖
if (DateDetail.checkTimeBetweenL(rule.getApplyStart(), oldRule.getInPoint(), oldRule.getOutPoint())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.ORDINARY));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.ORDINARY.getCode(), AttendanceTypeEnum.WORKOVERTIME.getCode()));
return;
}
//加班时间完全覆盖原来上班时段
if (DateDetail.checkBetween(oldRule.getInPoint(), rule.getApplyStart(), rule.getApplyEnd())
&& DateDetail.checkBetween(oldRule.getOutPoint(), rule.getApplyStart(), rule.getApplyEnd())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.ORDINARY));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.ORDINARY.getCode(), AttendanceTypeEnum.WORKOVERTIME.getCode()));
return;
}
//加班与普班时间边界连接
//加班结束时间与上班时段开始时间相同
if (oldRule.getInPoint().compareTo(rule.getApplyEnd()) == 0) {
oldRule.setInUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
rule.setOutUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
}
//加班开始时间与上班时段结束时间相同
if (oldRule.getOutPoint().compareTo(rule.getApplyStart()) == 0) {
oldRule.setOutUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
rule.setInUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
}
rule.insertTrue();
//完全没交集
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
log.error("新增加班与原排班时段中间没交集{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successNailBuild(rule));
});
return Boolean.TRUE;
}
}

View File

@@ -0,0 +1,159 @@
package jnpf.attendance.service.handle.rule;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import jnpf.attendance.service.RuleProcessor;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 处理历史排休
*/
@Component
@Slf4j
public class RestRuleProcessor extends RuleProcessor {
@Override
public void ruleArrangementHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> currDailyRule, List<DailyRuleResultVo> resultList) {
Map<Integer, List<FtbAttendanceDailyRule>> collect = hisDailyRules.stream().collect(Collectors.groupingBy(FtbAttendanceDailyRule::getAttendanceType));
List<FtbAttendanceDailyRule> ftbAttendanceDailyRules = CollUtil.newArrayList();
if (collect.containsKey(AttendanceTypeEnum.DEFAULT.getCode())) {
hisDailyRules.removeAll(collect.get(AttendanceTypeEnum.DEFAULT.getCode()));
}
if (collect.containsKey(AttendanceTypeEnum.REST.getCode())) {
ftbAttendanceDailyRules.addAll(collect.getOrDefault(AttendanceTypeEnum.REST.getCode(), List.of()).stream().filter(rule -> !rule.getIsInsert()).collect(Collectors.toList()));
}
if (collect.containsKey(AttendanceTypeEnum.HOLIDAYS.getCode())) {
ftbAttendanceDailyRules.addAll(collect.get(AttendanceTypeEnum.HOLIDAYS.getCode()));
}
if (collect.containsKey(AttendanceTypeEnum.DEDUCTION_HOLIDAYS.getCode())) {
ftbAttendanceDailyRules.addAll(collect.get(AttendanceTypeEnum.DEDUCTION_HOLIDAYS.getCode()));
}
if (collect.containsKey(AttendanceTypeEnum.EXCHANGE_HOLIDAYS.getCode())) {
ftbAttendanceDailyRules.addAll(collect.get(AttendanceTypeEnum.EXCHANGE_HOLIDAYS.getCode()));
}
if (CollUtil.isNotEmpty(ftbAttendanceDailyRules)) {
Iterator<FtbAttendanceDailyRule> iterator = currDailyRule.iterator();
while (iterator.hasNext()) {
FtbAttendanceDailyRule rule = iterator.next();
//新增清除
if (clearHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
if (stepOutHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
if (Objects.equals(AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType())) {
if (!hisDailyRules.contains(rule)) {
rule.setApplyViewEnable(0);
rule.insertTrue();
hisDailyRules.add(rule);
}
continue;
}
if (Objects.equals(AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType())) {
if (!hisDailyRules.contains(rule)) {
rule.setApplyViewEnable(1);
rule.insertTrue();
hisDailyRules.add(rule);
resultList.add(DailyRuleResultVo.successBuild(rule));
}
continue;
}
if (Objects.equals(AttendanceTypeEnum.REST.getCode(), rule.getAttendanceType()) || Objects.equals(AttendanceTypeEnum.ORDINARY.getCode(), rule.getAttendanceType())) {
log.error("新增{}覆盖原来休{}",AttendanceTypeEnum.getEnum(rule.getAttendanceType()).getMsg(), JSON.toJSONString(rule));
ftbAttendanceDailyRules.forEach(oldRule -> {
hisDailyRules.remove(oldRule);
resultList.add(DailyRuleResultVo.successRestBuild(oldRule, rule, rule.getPeriodWorkDay()));
});
if (!hisDailyRules.contains(rule)) {
rule.setApplyViewEnable(1);
hisDailyRules.add(rule);
}
continue;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
resultList.add(DailyRuleResultVo.successRestBuild(oldRule, rule, oldRule.getPeriodWorkDay()));
});
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
if (!Objects.equals(AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType())) {
rule.setApplyViewEnable(1);
}
hisDailyRules.add(rule);
}
}
}
if (Objects.nonNull(nextRuleProcessor)) {
nextRuleProcessor.ruleArrangementHandle(hisDailyRules, currDailyRule, resultList);
}
}
/**
* 新增外出、出差申请
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean stepOutHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增请假
if (!Objects.equals(AttendanceTypeEnum.BUSINESS_TRIP.getCode(), rule.getAttendanceType()) && !Objects.equals(AttendanceTypeEnum.STEP_OUT.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//新加入数据不做处理
if (oldRule.getIsInsert()) {
return;
}
rule.setShiftId(oldRule.getShiftId());
rule.setPeriodId(oldRule.getPeriodId());
rule.setApplyViewEnable(0);
rule.insertTrue();
oldRule.setInPoint(rule.getInPoint());
oldRule.setOutPoint(rule.getOutPoint());
oldRule.setInStepOutType(1);
oldRule.setOutStepOutType(1);
oldRule.setInStepOutApplyId(rule.getApplyId());
oldRule.setOutStepOutApplyId(rule.getApplyId());
oldRule.setApplyViewEnable(rule.getAttendanceType());
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
log.error("新增外出、出差申请标记原排休时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
});
return Boolean.TRUE;
}
/**
* 新增清除
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean clearHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增清除
if (!Objects.equals(AttendanceTypeEnum.CLEAR.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
resultList.add(DailyRuleResultVo.successBuild(oldRule));
hisDailyRules.remove(oldRule);
});
return Boolean.TRUE;
}
}

View File

@@ -0,0 +1,177 @@
package jnpf.attendance.service.handle.rule;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import jnpf.attendance.service.RuleProcessor;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import jnpf.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 处理历史出差、外出申请
*/
@Component
@Slf4j
public class StepOutRuleProcessor extends RuleProcessor {
@Override
public void ruleArrangementHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> currDailyRule, List<DailyRuleResultVo> resultList) {
Map<Integer, List<FtbAttendanceDailyRule>> collect = hisDailyRules.stream().collect(Collectors.groupingBy(FtbAttendanceDailyRule::getAttendanceType));
List<FtbAttendanceDailyRule> ftbAttendanceDailyRules = CollUtil.newArrayList();
if (collect.containsKey(AttendanceTypeEnum.BUSINESS_TRIP.getCode())) {
ftbAttendanceDailyRules.addAll(collect.get(AttendanceTypeEnum.BUSINESS_TRIP.getCode()));
}
if (collect.containsKey(AttendanceTypeEnum.STEP_OUT.getCode())) {
ftbAttendanceDailyRules.addAll(collect.get(AttendanceTypeEnum.STEP_OUT.getCode()));
}
if (CollUtil.isNotEmpty(ftbAttendanceDailyRules)) {
currDailyRule.forEach(rule -> {
//新增清除
if (clearHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
return;
}
if (!hisDailyRules.contains(rule) && !rule.getIsInsert()) {
hisDailyRules.add(rule);
}
});
Iterator<FtbAttendanceDailyRule> iterator = currDailyRule.iterator();
while (iterator.hasNext()) {
FtbAttendanceDailyRule rule = iterator.next();
//新增清除
if (Objects.equals(AttendanceTypeEnum.CLEAR.getCode(), rule.getAttendanceType())) {
continue;
}
daysStepOutHandle(hisDailyRules, resultList, ftbAttendanceDailyRules, rule);
housesStepOutHandle(hisDailyRules, resultList, ftbAttendanceDailyRules, rule);
}
}
if (Objects.nonNull(nextRuleProcessor)) {
nextRuleProcessor.ruleArrangementHandle(hisDailyRules, currDailyRule, resultList);
}
}
/**
* 处理单位为天的外出、出差规则冲突
* 该方法用于处理在已有的日常规则结果列表中,新加入的外出或出差规则与已有规则之间的冲突
* 如果新规则与已有规则冲突且为外出或出差类型,则记录错误日志并添加失败结果到列表中
* 如果不冲突,则更新新旧规则的申请查看权限,并添加成功结果到列表中
*
* @param resultList 日常规则结果列表,用于存储处理结果
* @param ftbAttendanceDailyRules 已有的日常规则列表,用于比较和更新
* @param rule 新加入的日常规则,用于检查冲突和更新
*/
private void daysStepOutHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<DailyRuleResultVo> resultList, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule) {
List<FtbAttendanceDailyRule> collect = ftbAttendanceDailyRules.stream().filter(oldRule -> Objects.equals(oldRule.getApplyUnit(), 2) || Objects.isNull(oldRule.getApplyUnit())).collect(Collectors.toList());
collect.forEach(oldRule -> {
if (StringUtil.equals(oldRule.getId(), rule.getId())) {
return;
}
if (Objects.equals(AttendanceTypeEnum.STEP_OUT.getCode(), rule.getAttendanceType()) || Objects.equals(AttendanceTypeEnum.BUSINESS_TRIP.getCode(), rule.getAttendanceType())) {
log.error(AttendanceConstant.getSchedulingResult(rule.getUserId(), rule.getDay(), AttendanceTypeEnum.getMsg(oldRule.getAttendanceType()), AttendanceTypeEnum.getMsg(rule.getAttendanceType())));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, oldRule.getAttendanceType(), rule.getAttendanceType()));
log.error("新增外出、出差申请与原外出、出差申请冲突{}", JSON.toJSONString(rule));
return;
}
rule.setApplyViewEnable(oldRule.getAttendanceType());
rule.setInStepOutType(1);
rule.setOutStepOutType(1);
rule.setInStepOutApplyId(oldRule.getApplyId());
rule.setOutStepOutApplyId(oldRule.getApplyId());
oldRule.setApplyViewEnable(0);
log.error("原外出、出差申请标记新增排班时段{}", JSON.toJSONString(rule));
if (!oldRule.getIsInsert() && !hisDailyRules.contains(rule) && !rule.getIsInsert()) {
hisDailyRules.add(rule);
rule.insertTrue();
}
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
});
}
/**
* 处理单位为小时的外出、出差规则冲突
* 该方法用于处理在已有的日常规则结果列表中,新加入的外出或出差规则与已有规则之间的冲突
* 如果新规则与已有规则冲突且为外出或出差类型,则记录错误日志并添加失败结果到列表中
* 如果不冲突,则更新新旧规则的申请查看权限,并添加成功结果到列表中
*
* @param resultList 日常规则结果列表,用于存储处理结果
* @param ftbAttendanceDailyRules 已有的日常规则列表,用于比较和更新
* @param rule 新加入的日常规则,用于检查冲突和更新
*/
private void housesStepOutHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<DailyRuleResultVo> resultList, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule) {
List<FtbAttendanceDailyRule> collect = ftbAttendanceDailyRules.stream().filter(oldRule -> Objects.equals(oldRule.getApplyUnit(), 1) && !oldRule.equals(rule)).collect(Collectors.toList());
collect.forEach(stepOutRule -> {
if (Objects.equals(rule.getAttendanceType(), AttendanceTypeEnum.STEP_OUT.getCode()) || Objects.equals(rule.getAttendanceType(), AttendanceTypeEnum.BUSINESS_TRIP.getCode())) {
if (!stepOutRule.getOutPoint().before(rule.getInPoint()) && !stepOutRule.getInPoint().after(rule.getOutPoint())) {
resultList.add(DailyRuleResultVo.failBuild(stepOutRule, rule, stepOutRule.getAttendanceType(), rule.getAttendanceType()));
log.error("新增小时外出申请与原外出申请冲突{}", JSON.toJSONString(rule));
return;
}
}
if(Objects.equals(rule.getAttendanceType(), AttendanceTypeEnum.REST.getCode()) && Objects.isNull(rule.getInPoint()) ){
rule.setApplyViewEnable(0);
if (!hisDailyRules.contains(rule) && !rule.getIsInsert()) {
hisDailyRules.add(rule);
rule.insertTrue();
}
return;
}
//原小时外出没命中已有班次数据,隐藏外出申请
if (stepOutRule.getOutPoint().before(rule.getInPoint())
|| stepOutRule.getInPoint().after(rule.getOutPoint())
|| stepOutRule.getInPoint().after(rule.getInPoint()) && stepOutRule.getOutPoint().before(rule.getOutPoint())) {
if (!stepOutRule.getIsInsert() && !hisDailyRules.contains(rule) && !rule.getIsInsert()) {
hisDailyRules.add(rule);
rule.insertTrue();
}
log.error("排班数据未命中小时外出申请或者外出数据完全被排班数据覆盖,过滤{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successNailBuild(rule));
return;
}
stepOutRule.setApplyViewEnable(0);
rule.setApplyViewEnable(stepOutRule.getAttendanceType());
//原小时外出数据覆盖现在新增排班数据上班时间
if (!stepOutRule.getInPoint().after(rule.getInPoint())) {
rule.setInStepOutType(1);
rule.setInStepOutApplyId(stepOutRule.getApplyId());
}
//原小时外出数据覆盖现在新增排班数据下班时间
if (!stepOutRule.getOutPoint().before(rule.getOutPoint())) {
rule.setOutStepOutType(1);
rule.setOutStepOutApplyId(stepOutRule.getApplyId());
}
if (!stepOutRule.getIsInsert() && !hisDailyRules.contains(rule) && !rule.getIsInsert()) {
hisDailyRules.add(rule);
rule.insertTrue();
}
log.error("新增外出、出差申请标记排班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(stepOutRule, rule));
});
}
/**
* 新增清除
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean clearHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增清除
if (!Objects.equals(AttendanceTypeEnum.CLEAR.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> oldRule.setApplyViewEnable(oldRule.getAttendanceType()));
return Boolean.TRUE;
}
}

View File

@@ -0,0 +1,487 @@
package jnpf.attendance.service.handle.rule;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import jnpf.attendance.service.RuleProcessor;
import jnpf.constants.AttendanceConstant;
import jnpf.entity.attendance.FtbAttendanceDailyRule;
import jnpf.enums.attendance.AttendanceTypeEnum;
import jnpf.enums.attendance.LeaveUnitEnum;
import jnpf.enums.attendance.v2.WorkBoundaryCoverageEnum;
import jnpf.model.attendance.vo.DailyRuleResultVo;
import jnpf.util.DateDetail;
import jnpf.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
/**
* 处理历史加班申请
*/
@Component
@Slf4j
public class WorkOvertimeRuleProcessor extends RuleProcessor {
@Override
public void ruleArrangementHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> currDailyRule, List<DailyRuleResultVo> resultList) {
Map<Integer, List<FtbAttendanceDailyRule>> collect = hisDailyRules.stream().collect(Collectors.groupingBy(FtbAttendanceDailyRule::getAttendanceType));
List<FtbAttendanceDailyRule> ftbAttendanceDailyRules = collect.getOrDefault(AttendanceTypeEnum.WORKOVERTIME.getCode(), List.of()).stream().filter(rule -> Objects.isNull(rule.getIsInsert()) || !rule.getIsInsert()).collect(Collectors.toList());
if (CollUtil.isNotEmpty(ftbAttendanceDailyRules)) {
if (currDailyRule.stream().allMatch(rule -> Objects.equals(AttendanceTypeEnum.ORDINARY.getCode(), rule.getAttendanceType())
|| Objects.equals(AttendanceTypeEnum.CLEAR.getCode(), rule.getAttendanceType()))) {
ftbAttendanceDailyRules.forEach(oldRule -> {
oldRule.setOutUnbounded(0);
oldRule.setInUnbounded(0);
oldRule.setApplyViewEnable(1);
});
}
Iterator<FtbAttendanceDailyRule> iterator = currDailyRule.iterator();
Boolean isRecover = Boolean.TRUE;
while (iterator.hasNext()) {
FtbAttendanceDailyRule rule = iterator.next();
//新增清除
if (clearHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增排休
if (restHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增上班
if (ordinaryHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList, isRecover)) {
isRecover = Boolean.FALSE;
continue;
}
//新增加班
if (workOvertimeHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增请假
if (leaveHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
//新增外出、出差
if (stepOutHandle(hisDailyRules, ftbAttendanceDailyRules, rule, resultList)) {
continue;
}
}
}
if (Objects.nonNull(nextRuleProcessor)) {
nextRuleProcessor.ruleArrangementHandle(hisDailyRules, currDailyRule, resultList);
}
}
/**
* 新增清除
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean clearHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增清除
if (!Objects.equals(AttendanceTypeEnum.CLEAR.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
recoverHandle(hisDailyRules, ftbAttendanceDailyRules);
return Boolean.TRUE;
}
/**
* 恢复原加班
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
*/
private void recoverHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules) {
//恢复原加班
hisDailyRules.removeAll(hisDailyRules.stream().filter(rule -> !rule.getIsInsert() && Objects.equals(rule.getAttendanceType(), AttendanceTypeEnum.ORDINARY.getCode())).collect(Collectors.toList()));
Map<String, List<FtbAttendanceDailyRule>> collect = ftbAttendanceDailyRules.stream().collect(Collectors.groupingBy(FtbAttendanceDailyRule::getApplyId));
collect.forEach((k, rules) -> {
FtbAttendanceDailyRule ftbAttendanceDailyRule = rules.stream().sorted(Comparator.comparing(FtbAttendanceDailyRule::getInPoint)).findFirst().orElse(null);
ftbAttendanceDailyRule.setInPoint(ftbAttendanceDailyRule.getApplyStart());
ftbAttendanceDailyRule.setOutPoint(ftbAttendanceDailyRule.getApplyEnd());
hisDailyRules.removeAll(rules);
hisDailyRules.add(ftbAttendanceDailyRule);
});
}
/**
* 新增外出、出差申请
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean stepOutHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增请假
if (!Objects.equals(AttendanceTypeEnum.BUSINESS_TRIP.getCode(), rule.getAttendanceType()) && !Objects.equals(AttendanceTypeEnum.STEP_OUT.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//过滤隐藏规则
if (Objects.equals(oldRule.getApplyViewEnable(), 0)) {
return;
}
//新加入数据不做处理
if (oldRule.getIsInsert()) {
return;
}
rule.setShiftId(oldRule.getShiftId());
rule.setPeriodId(oldRule.getPeriodId());
rule.setApplyViewEnable(0);
//原小时外出没命中已有班次数据,隐藏外出申请
if (rule.getOutPoint().before(oldRule.getInPoint())
|| rule.getInPoint().after(oldRule.getOutPoint())
|| rule.getInPoint().after(oldRule.getInPoint()) && rule.getOutPoint().before(oldRule.getOutPoint())) {
if (!rule.getIsInsert()) {
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
}
log.error("新增排班数据未命中小时外出申请或者外出数据完全被排班数据覆盖,过滤{}", JSON.toJSONString(rule));
return;
}
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
rule.setApplyViewEnable(0);
oldRule.setApplyViewEnable(rule.getAttendanceType());
//原小时外出数据覆盖现在新增排班数据上班时间
if (!rule.getInPoint().after(oldRule.getInPoint())) {
oldRule.setInStepOutType(1);
oldRule.setInStepOutApplyId(rule.getApplyId());
}
//原小时外出数据覆盖现在新增排班数据下班时间
if (!rule.getOutPoint().before(oldRule.getOutPoint())) {
oldRule.setOutStepOutType(1);
oldRule.setOutStepOutApplyId(rule.getApplyId());
}
log.error("新增外出、出差申请标记原加班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
});
return Boolean.TRUE;
}
/**
* 新增请假
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean leaveHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增请假
if (!Objects.equals(AttendanceTypeEnum.LEAVE.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
//全天假与加班冲突
if (Objects.equals(rule.getApplyUnit(), LeaveUnitEnum.DAY.getCode())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.WORKOVERTIME));
FtbAttendanceDailyRule oldRule = ftbAttendanceDailyRules.stream().findFirst().orElse(null);
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType()));
return Boolean.TRUE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//新加入数据不做处理
if (oldRule.getIsInsert()) {
return;
}
rule.setSelfGroup(oldRule.getSelfGroup());
//完全覆盖
//原来加班时段完全覆盖请假时间
if (DateDetail.checkBetween(rule.getApplyStart(), oldRule.getInPoint(), oldRule.getOutPoint())
&& DateDetail.checkBetween(rule.getApplyEnd(), oldRule.getInPoint(), oldRule.getOutPoint())
|| (rule.getApplyStart().compareTo(oldRule.getInPoint()) == 0 && rule.getApplyEnd().compareTo(oldRule.getOutPoint()) == 0)) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.WORKOVERTIME));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType()));
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkBetween(rule.getApplyEnd(), oldRule.getInPoint(), oldRule.getOutPoint())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.WORKOVERTIME));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType()));
return;
}
//结束部分覆盖
if (DateDetail.checkBetween(rule.getApplyStart(), oldRule.getInPoint(), oldRule.getOutPoint())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.WORKOVERTIME));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType()));
return;
}
//请假完全覆盖加班
if (DateDetail.checkTimeBetweenL(oldRule.getApplyStart(), rule.getInPoint(), rule.getOutPoint())
&& DateDetail.checkTimeBetweenR(oldRule.getApplyEnd(), rule.getInPoint(), rule.getOutPoint())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.WORKOVERTIME));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType()));
return;
}
rule.insertTrue();
//完全没交集
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
log.error("请假时间完全与原来加班时段完全没交集{}", JSON.toJSONString(rule));
});
return Boolean.TRUE;
}
/**
* 新增加班
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean workOvertimeHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增加班
if (!Objects.equals(AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//新加入数据不做处理
if (oldRule.getIsInsert()) {
return;
}
rule.setSelfGroup(oldRule.getSelfGroup());
//新增加班时间完全覆盖原来加班时段
if (DateDetail.checkTimeBetween(oldRule.getApplyStart(), rule.getInPoint(), rule.getOutPoint())
&& DateDetail.checkTimeBetween(oldRule.getApplyEnd(), rule.getInPoint(), rule.getOutPoint())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.WORKOVERTIME));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType()));
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkBetween(rule.getApplyEnd(), oldRule.getInPoint(), oldRule.getOutPoint())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.WORKOVERTIME));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType()));
return;
}
//结束部分覆盖
if (DateDetail.checkBetween(rule.getApplyStart(), oldRule.getInPoint(), oldRule.getOutPoint())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.WORKOVERTIME));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType()));
return;
}
//新增加班时段处于原加班时段中间
if (DateDetail.checkTimeBetweenL(rule.getApplyStart(), oldRule.getInPoint(), oldRule.getOutPoint())
&& DateDetail.checkTimeBetweenR(rule.getApplyEnd(), oldRule.getInPoint(), oldRule.getOutPoint())) {
log.error(AttendanceConstant.getApplyResult(rule.getUserId(), AttendanceConstant.WORKOVERTIME));
resultList.add(DailyRuleResultVo.failBuild(oldRule, rule, AttendanceTypeEnum.WORKOVERTIME.getCode(), rule.getAttendanceType()));
return;
}
//加班与普班时间边界连接
//加班开始时间与上班时段结束时间相同
if (oldRule.getInPoint().compareTo(rule.getOutPoint()) == 0) {
oldRule.setInUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
rule.setOutUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
}
//加班结束时间与上班时段开始时间相同
if (oldRule.getOutPoint().compareTo(rule.getInPoint()) == 0) {
oldRule.setOutUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
rule.setInUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
}
//完全没交集
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
log.error("新增加班时段与原加班时段没交集{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
});
return Boolean.TRUE;
}
/**
* 新增上班
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean ordinaryHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList, Boolean isRecover) {
if (!Objects.equals(AttendanceTypeEnum.ORDINARY.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
if (isRecover) {
recoverHandle(hisDailyRules, ftbAttendanceDailyRules);
}
//新增上班
ftbAttendanceDailyRules = hisDailyRules.stream().filter(rule1 -> Objects.equals(rule1.getAttendanceType(), AttendanceTypeEnum.WORKOVERTIME.getCode())).collect(Collectors.toList());
ftbAttendanceDailyRules.forEach(oldRule -> {
//新加入数据不做处理
if (oldRule.getIsInsert()) {
return;
}
//原加班时段处于新增上班时段中间
if (DateDetail.checkTimeBetween(oldRule.getInPoint(), rule.getInPoint(), rule.getOutPoint())
&& DateDetail.checkTimeBetween(oldRule.getOutPoint(), rule.getInPoint(), rule.getOutPoint())) {
oldRule.setApplyViewEnable(0);
oldRule.setShiftId(rule.getShiftId());
oldRule.setPeriodId(rule.getPeriodId());
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
log.error("新增上班时段完全覆盖原来加班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkBetween(rule.getOutPoint(), oldRule.getInPoint(), oldRule.getOutPoint())
&& rule.getInPoint().compareTo(oldRule.getApplyStart()) <= 0) {
oldRule.setInPoint(rule.getOutPoint());
oldRule.setInUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
rule.setOutUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
oldRule.setShiftId(rule.getShiftId());
oldRule.setPeriodId(rule.getPeriodId());
oldRule.setApplyViewEnable(1);
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
log.error("新增上班时段开始部分覆盖原来加班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//结束部分覆盖
if (DateDetail.checkBetween(rule.getInPoint(), oldRule.getInPoint(), oldRule.getOutPoint())
&& rule.getOutPoint().compareTo(oldRule.getApplyEnd()) >= 0) {
oldRule.setOutPoint(rule.getInPoint());
oldRule.setOutUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
rule.setInUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
oldRule.setShiftId(rule.getShiftId());
oldRule.setPeriodId(rule.getPeriodId());
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
log.error("新增上班时段结束部分覆盖原来加班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//原来加班时段完全覆盖新增上班时间
if (DateDetail.checkTimeBetween(rule.getInPoint(), oldRule.getInPoint(), oldRule.getOutPoint())
&& DateDetail.checkTimeBetween(rule.getOutPoint(), oldRule.getInPoint(), oldRule.getOutPoint())) {
oldRule.setShiftId(rule.getShiftId());
oldRule.setPeriodId(rule.getPeriodId());
FtbAttendanceDailyRule oldRule1 = BeanUtil.toBean(oldRule, FtbAttendanceDailyRule.class);
oldRule.setOutPoint(rule.getInPoint());
oldRule.setOutUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
rule.setInUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
rule.setOutUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
oldRule1.setInPoint(rule.getOutPoint());
oldRule1.setInUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
oldRule1.setId(RandomUtil.uuId());
oldRule1.setApplyViewEnable(1);
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
hisDailyRules.add(oldRule1);
log.error("新增上班时间处于原来加班时段中间{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//加班与普班时间边界连接
//加班开始时间与上班时段结束时间相同
if (oldRule.getInPoint().compareTo(rule.getOutPoint()) == 0) {
oldRule.setInUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
rule.setOutUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
}
//加班结束时间与上班时段开始时间相同
if (oldRule.getOutPoint().compareTo(rule.getInPoint()) == 0) {
oldRule.setOutUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
rule.setInUnbounded(WorkBoundaryCoverageEnum.OVERTIME_COVERED.getCode());
}
//完全没交集
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
log.error("新增上班时段与原加班时段没交集{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
});
return Boolean.TRUE;
}
/**
* 新增排休
*
* @param hisDailyRules 历史规则
* @param ftbAttendanceDailyRules 新增规则集合
* @param rule 当前规则
*/
private Boolean restHandle(List<FtbAttendanceDailyRule> hisDailyRules, List<FtbAttendanceDailyRule> ftbAttendanceDailyRules, FtbAttendanceDailyRule rule, List<DailyRuleResultVo> resultList) {
//新增排休
if (!Objects.equals(AttendanceTypeEnum.REST.getCode(), rule.getAttendanceType())
&& !Objects.equals(AttendanceTypeEnum.HOLIDAYS.getCode(), rule.getAttendanceType())
&& !Objects.equals(AttendanceTypeEnum.DEDUCTION_HOLIDAYS.getCode(), rule.getAttendanceType())
&& !Objects.equals(AttendanceTypeEnum.EXCHANGE_HOLIDAYS.getCode(), rule.getAttendanceType())) {
return Boolean.FALSE;
}
recoverHandle(hisDailyRules, ftbAttendanceDailyRules);
//休不存在打卡时间默认为当天最早、最后时间
rule.setInPoint(Objects.isNull(rule.getInPoint()) ? DateUtil.beginOfDay(rule.getDay()) : rule.getInPoint());
rule.setOutPoint(Objects.isNull(rule.getOutPoint()) ? DateUtil.endOfDay(rule.getDay()) : rule.getOutPoint());
rule.insertTrue();
if (!hisDailyRules.contains(rule)) {
hisDailyRules.add(rule);
}
ftbAttendanceDailyRules.forEach(oldRule -> {
//原加班时段处于休息时段中间
if (DateDetail.checkTimeBetween(oldRule.getApplyStart(), rule.getInPoint(), rule.getOutPoint())
&& DateDetail.checkTimeBetween(oldRule.getApplyEnd(), rule.getInPoint(), rule.getOutPoint())) {
oldRule.setInPoint(oldRule.getApplyStart());
oldRule.setOutPoint(oldRule.getApplyEnd());
log.error("新增休完全覆盖原来加班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//部分覆盖
//开始部分覆盖
if (DateDetail.checkTimeBetween(rule.getOutPoint(), oldRule.getApplyStart(), oldRule.getApplyEnd())
&& rule.getInPoint().compareTo(oldRule.getApplyStart()) <= 0) {
oldRule.setInPoint(oldRule.getApplyStart());
oldRule.setApplyViewEnable(1);
log.error("新增休开始部分覆盖原来加班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//结束部分覆盖
if (DateDetail.checkTimeBetween(rule.getInPoint(), oldRule.getApplyStart(), oldRule.getApplyEnd())
&& rule.getOutPoint().compareTo(oldRule.getApplyEnd()) >= 0) {
oldRule.setOutPoint(oldRule.getApplyEnd());
log.error("新增休结束部分覆盖原来加班时段{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
//原来加班时段完全覆盖休时间
if (DateDetail.checkTimeBetween(rule.getInPoint(), oldRule.getApplyStart(), oldRule.getApplyEnd())
&& DateDetail.checkTimeBetween(rule.getOutPoint(), oldRule.getApplyStart(), oldRule.getApplyEnd())) {
log.error("原来加班时段完全覆盖新增休时间{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
return;
}
oldRule.setShiftId(rule.getShiftId());
oldRule.setPeriodId(rule.getPeriodId());
//完全没交集
log.error("新增休与原加班时段没交集{}", JSON.toJSONString(rule));
resultList.add(DailyRuleResultVo.successBuild(oldRule, rule));
});
log.error("新增排休与原加班时段,过滤新增排休{}", JSON.toJSONString(rule));
return Boolean.TRUE;
}
}