You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
hrm-attendance/test/TestGetClockInPoint.java

454 lines
25 KiB
Java

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import com.engine.attendance.attendanceanalysis.cmd.GetClockInPointCmd;
import com.engine.attendance.attendanceanalysis.service.UtilService;
import com.engine.attendance.attendanceanalysis.service.impl.UtilServiceImpl;
import com.engine.attendance.attendanceanalysis.wrapper.AttendanceAnalysisWrapper;
import com.engine.attendance.enums.AccountingUnitEnum;
import com.engine.attendance.enums.CheckBoxEnum;
import com.engine.attendance.enums.ClassSegmentTypeEnum;
import com.engine.attendance.enums.ClockPointEnum;
import com.engine.common.util.DateUtil;
import com.engine.common.util.ServiceUtil;
import com.engine.common.util.Utils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import weaver.general.Util;
import java.time.ZoneOffset;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class TestGetClockInPoint {
public static void main(String[] args) {
List<Map<String,Object>> schedulingList = Lists.newArrayList();
schedulingList.add(new HashMap(){{
put("edsc","9.50");
put("bdlx","0");
put("jsdk","1");
put("tqdkfzs","720");
put("sfkt","1");
put("dtjssj","12:00");
put("zddxfz","30");
put("bcxx","25");
put("dxhs","5");
put("bcsdxx","09:00-13:00|13:00-18:30");
put("sfdx","0");
put("dtkssj","09:00");
put("thdkfzs","720");
put("ksdk","0");
put("rqlx","11");
}});
schedulingList.add(new HashMap(){{
put("edsc","9.50");
put("bdlx","1");
put("jsdk","0");
put("tqdkfzs","120");
put("sfkt","1");
put("dtjssj","13:00");
put("zddxfz","30");
put("bcxx","25");
put("dxhs","5");
put("bcsdxx","09:00-13:00|13:00-18:30");
put("sfdx","1");
put("dtkssj","12:00");
put("thdkfzs","120");
put("ksdk","0");
put("rqlx","11");
}});
schedulingList.add(new HashMap(){{
put("edsc","9.50");
put("bdlx","0");
put("jsdk","0");
put("tqdkfzs","720");
put("sfkt","1");
put("dtjssj","18:00");
put("zddxfz","30");
put("bcxx","25");
put("dxhs","5");
put("bcsdxx","09:00-13:00|13:00-18:30");
put("sfdx","1");
put("dtkssj","13:00");
put("thdkfzs","720");
put("ksdk","1");
put("rqlx","11");
}});
schedulingList.add(new HashMap(){{
put("edsc","9.50");
put("bdlx","1");
put("jsdk","0");
put("tqdkfzs","120");
put("sfkt","1");
put("dtjssj","19:00");
put("zddxfz","30");
put("bcxx","25");
put("dxhs","5");
put("bcsdxx","09:00-13:00|13:00-18:30");
put("sfdx","1");
put("dtkssj","18:00");
put("thdkfzs","120");
put("ksdk","0");
put("rqlx","11");
}});
// schedulingList.add(new HashMap(){{
// put("edsc","9.50");
// put("bdlx","2");
// put("jsdk","1");
// put("tqdkfzs","60");
// put("sfkt","1");
// put("dtjssj","21:00");
// put("zddxfz","30");
// put("bcxx","25");
// put("dxhs","5");
// put("bcsdxx","09:00-13:00|13:00-18:30");
// put("sfdx","1");
// put("dtkssj","19:00");
// put("thdkfzs","120");
// put("ksdk","1");
// put("rqlx","11");
// }});
List<Map<String,Object>> dataList = Lists.newArrayList();
// dataList.add(new HashMap(){{
// put("signtime","11:20:00");
// put("id","48");
// put("userid","53");
// put("signdate","2023-11-12");
// }});
// dataList.add(new HashMap(){{
// put("signtime","13:20:00");
// put("id","48");
// put("userid","53");
// put("signdate","2023-11-12");
// }});
// dataList.add(new HashMap(){{
// put("signtime","18:29:00");
// put("id","48");
// put("userid","53");
// put("signdate","2023-11-12");
// }});
// dataList.add(new HashMap(){{
// put("signtime","19:08:00");
// put("id","48");
// put("userid","53");
// put("signdate","2023-11-12");
// }});
Map<String,Object> param = Maps.newHashMap();
List<Map<String,Object>> askForLeaveAndEvctionSchedule = Lists.newArrayList();
// askForLeaveAndEvctionSchedule.add(new HashMap(){{
// put("edsc","9.50");
// put("bdlx",ClassSegmentTypeEnum.ASK_FOR_LEAVE.getKey());
// put("jsdk","0");
// put("tqdkfzs","60");
// put("sfkt","1");
// put("dtjssj","18:00");
// put("zddxfz","30");
// put("bcxx","25");
// put("dxhs","5");
// put("bcsdxx","09:00-13:00|13:00-18:30");
// put("sfdx","1");
// put("dtkssj","11:00");
// put("thdkfzs","60");
// put("ksdk","0");
// put("rqlx","11");
// }});
param.put("analysisDate","2023-11-12");
param.put("scheduleResult",schedulingList);
param.put("clockInTimeList",dataList);
param.put("askForLeaveAndEvctionSchedule",askForLeaveAndEvctionSchedule);
// List<Map<String, Map<String,Object>>> collect = getClockInPoint("2023-11-12",schedulingList,dataList);
List<Map<String, Map<String,Object>>> collect = (List<Map<String, Map<String, Object>>>)new GetClockInPointCmd(param).execute(null).get("clcokInTimeData");
// Map<String,Object> clock = getNeedRecordClockInTime(collect);
// System.out.println(clock);
}
public static List<Map<String, Map<String,Object>>> getClockInPoint(String analysisDate, List<Map<String, Object>> needClockInSchedule, List<Map<String, Object>> clockInTimeList){
List<Map<String,Map<String,Object>>> clcokInTimeData = Lists.newArrayList();
for (Map<String, Object> needClockIn :needClockInSchedule){
if (CheckBoxEnum.CHECKED.getKey().equals(needClockIn.get("ksdk"))){
String dtkssj = analysisDate+" "+needClockIn.get("dtkssj");
String dtjssj = analysisDate+" "+needClockIn.get("dtjssj");
if (DateUtil.getTime(dtkssj).compareTo(DateUtil.getTime(dtjssj)) > 0){
dtjssj = DateUtil.AfterDay(analysisDate,1) +" "+needClockIn.get("dtjssj");
}
int tqdkfzs = Integer.valueOf(Util.null2String(needClockIn.get("tqdkfzs")));
Map<String,Map<String,Object>> ksdkNearestClcokInTime = Utils.getNearestClcokInTimeCmd(dtkssj,clockInTimeList);
String timeType = ClockPointEnum.EMPTY.getKey();
Map<String,Map<String,Object>> clcokInTimeMap = Maps.newHashMap();
if (ksdkNearestClcokInTime.get(ClockPointEnum.EQUAL.getKey()) != null){
timeType=ClockPointEnum.EQUAL.getKey();
}
if (ClockPointEnum.EMPTY.getKey().equals(timeType) && ksdkNearestClcokInTime.get(ClockPointEnum.BEFORE.getKey()) != null){
String clockInTime = ksdkNearestClcokInTime.get(ClockPointEnum.BEFORE.getKey()).get("signdate") +" "+ksdkNearestClcokInTime.get(ClockPointEnum.BEFORE.getKey()).get("signtime");
if (DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(DateUtil.beforeMinutes(dtkssj,tqdkfzs))) >=0){
//打卡时间大于等于最早打卡时间
timeType=ClockPointEnum.BEFORE.getKey();
}
}
if (ClockPointEnum.EMPTY.getKey().equals(timeType) && ksdkNearestClcokInTime.get(ClockPointEnum.AFTER.getKey()) != null){
String clockInTime = ksdkNearestClcokInTime.get(ClockPointEnum.AFTER.getKey()).get("signdate") +" "+ksdkNearestClcokInTime.get(ClockPointEnum.AFTER.getKey()).get("signtime");
if (DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(dtjssj)) < 0){
//打卡时间小于结束时间
timeType=ClockPointEnum.AFTER.getKey();
}
}
clcokInTimeMap.put(dtkssj+"|"+ClockPointEnum.START.getKey()+"|"+timeType,ksdkNearestClcokInTime.get(timeType));
clcokInTimeData.add(clcokInTimeMap);
}
if (CheckBoxEnum.CHECKED.getKey().equals(needClockIn.get("jsdk"))){
String dtkssj = analysisDate+" "+needClockIn.get("dtkssj");
String dtjssj = analysisDate+" "+needClockIn.get("dtjssj");
int thdkfzs = Integer.valueOf(Util.null2String(needClockIn.get("thdkfzs")));
if (DateUtil.getTime(dtkssj).compareTo(DateUtil.getTime(dtjssj)) > 0){
dtjssj = DateUtil.AfterDay(analysisDate,1) +" "+needClockIn.get("dtjssj");
}
Map<String,Map<String,Object>> jsdkNearestClcokInTime = Utils.getNearestClcokInTimeCmd(dtjssj,clockInTimeList);
String timeType = ClockPointEnum.EMPTY.getKey();
Map<String,Map<String,Object>> clcokInTimeMap = Maps.newHashMap();
if (jsdkNearestClcokInTime.get(ClockPointEnum.EQUAL.getKey()) != null){
timeType=ClockPointEnum.EQUAL.getKey();
}
if (ClockPointEnum.EMPTY.getKey().equals(timeType) && jsdkNearestClcokInTime.get(ClockPointEnum.AFTER.getKey()) != null){
String clockInTime = jsdkNearestClcokInTime.get(ClockPointEnum.AFTER.getKey()).get("signdate") +" "+jsdkNearestClcokInTime.get(ClockPointEnum.AFTER.getKey()).get("signtime");
if (DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(DateUtil.AfterMinutes(dtjssj,thdkfzs))) <=0){
timeType=ClockPointEnum.AFTER.getKey();
}
}
if (ClockPointEnum.EMPTY.getKey().equals(timeType) && jsdkNearestClcokInTime.get(ClockPointEnum.BEFORE.getKey()) != null){
String clockInTime = jsdkNearestClcokInTime.get(ClockPointEnum.BEFORE.getKey()).get("signdate") +" "+jsdkNearestClcokInTime.get(ClockPointEnum.BEFORE.getKey()).get("signtime");
if (DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(dtkssj)) >0){
timeType=ClockPointEnum.BEFORE.getKey();
}
}
clcokInTimeMap.put(dtjssj+"|"+ClockPointEnum.END.getKey()+"|"+timeType,jsdkNearestClcokInTime.get(timeType));
clcokInTimeData.add(clcokInTimeMap);
}
}
clcokInTimeData = clcokInTimeData.stream().sorted(Comparator.comparing(e->{
//卡点
String point = "";
//当天打卡数据
for (Map.Entry<String,Map<String,Object>> entry :e.entrySet()){
point = entry.getKey();
}
return DateUtil.getTime(point.split("\\|")[0]).toInstant(ZoneOffset.of("+8")).toEpochMilli();
})).collect(Collectors.toList());
//当弹性上下班时
if (needClockInSchedule.size() > 0){
//是否弹性
String sfdx = Util.null2String(needClockInSchedule.get(0).get("sfdx"));
//最大弹性分钟
int zddxfz = Integer.valueOf(Util.null2String(needClockInSchedule.get(0).get("zddxfz")));
//弹性核算
int dxhs = Integer.valueOf(Util.null2String(needClockInSchedule.get(0).get("dxhs")));
if (CheckBoxEnum.CHECKED.getKey().equals(sfdx)){
//上下班弹性
List<Map<String, Object>> needClockInStartList = needClockInSchedule.stream().filter(e -> ClassSegmentTypeEnum.WORK_TIME.getKey().equals(e.get("bdlx")) && CheckBoxEnum.CHECKED.getKey().equals(e.get("ksdk"))).collect(Collectors.toList());
List<Map<String, Object>> needClockInEndList = needClockInSchedule.stream().filter(e -> ClassSegmentTypeEnum.WORK_TIME.getKey().equals(e.get("bdlx")) && CheckBoxEnum.CHECKED.getKey().equals(e.get("jsdk"))).collect(Collectors.toList());
if (needClockInStartList.size()>0 && needClockInEndList.size()>0){
Map<String, Object> ksdkMap = needClockInStartList.get(0);
String kssjStart = analysisDate + " " +Util.null2String(ksdkMap.get("dtkssj"));
String jssjStart = analysisDate +" "+Util.null2String(ksdkMap.get("dtjssj"));
Map<String, Object> jsdkMap = needClockInEndList.get(needClockInEndList.size()-1);
int thdkfzs = Integer.valueOf(Util.null2String(jsdkMap.get("thdkfzs")));
String kssjEnd = analysisDate + " " +Util.null2String(jsdkMap.get("dtkssj"));
String jssjEnd = analysisDate +" "+Util.null2String(jsdkMap.get("dtjssj"));
if (ksdkMap != jsdkMap){
if (DateUtil.getTime(kssjStart).compareTo(DateUtil.getTime(jssjStart)) > 0){
kssjStart = DateUtil.beforeDay(analysisDate,1)+" "+Util.null2String(ksdkMap.get("dtkssj"));
}
if (DateUtil.getTime(kssjEnd).compareTo(DateUtil.getTime(jssjEnd)) > 0){
jssjEnd = DateUtil.AfterDay(analysisDate,1)+" "+Util.null2String(jsdkMap.get("dtjssj"));
}
}else {
jssjEnd = DateUtil.AfterDay(analysisDate,1)+" "+Util.null2String(jsdkMap.get("dtjssj"));
}
//弹性上班卡
String flexibleWork = "";
for (int i=0;i<clcokInTimeData.size();i++){
Map<String,Map<String,Object>> clcokInTimeMap = clcokInTimeData.get(i);
//卡点
String point = "";
//当天打卡数据
Map<String,Object> clcokInTime = null;
for (Map.Entry<String,Map<String,Object>> entry :clcokInTimeMap.entrySet()){
point = entry.getKey();
clcokInTime = entry.getValue();
}
//需要计算的班次打卡时间点
String pointTime = point.split("\\|")[0];
//start开始打卡时间点end结束打卡时间点
String pointType = point.split("\\|")[1];
//empty:漏卡equal:打卡时间和班次时间相等before打卡时间在班次时间之前after打卡时间在班次时间之后
String timeType = point.split("\\|")[2];
if (pointTime.equals(kssjStart) && ClockPointEnum.START.getKey().equals(pointType) && clcokInTime != null){
String signTime = clcokInTime.get("signdate")+" "+clcokInTime.get("signtime");
//该卡点是弹性开始时间
if (ClockPointEnum.BEFORE.getKey().equals(timeType)){
int betWeenTime = DateUtil.getBetWeenMinutes(signTime,kssjStart);
String newPonit = point;
if (betWeenTime <= zddxfz){
betWeenTime = Double.valueOf(Utils.getItemdurationDown(5.0, AccountingUnitEnum.MINUTES.getKey(),betWeenTime,AccountingUnitEnum.MINUTES)).intValue();
flexibleWork = DateUtil.beforeMinutes(kssjStart,betWeenTime);
newPonit = pointTime+"|"+pointType+"|"+ClockPointEnum.EQUAL.getKey()+"|"+flexibleWork;
}else if (betWeenTime > zddxfz){
newPonit = point +"|"+DateUtil.beforeMinutes(kssjStart,zddxfz);
flexibleWork = DateUtil.beforeMinutes(kssjStart,zddxfz);
}
clcokInTimeMap.remove(point);
clcokInTimeMap.put(newPonit,clcokInTime);
}else if (ClockPointEnum.AFTER.getKey().equals(timeType)){
//迟到
String newPonit = point;
int betWeenTime = DateUtil.getBetWeenMinutes(kssjStart,signTime);
if (betWeenTime <= zddxfz){
betWeenTime = Double.valueOf(Utils.getItemduration(5.0, AccountingUnitEnum.MINUTES.getKey(),betWeenTime,AccountingUnitEnum.MINUTES)).intValue();
flexibleWork = DateUtil.AfterMinutes(kssjStart,betWeenTime);
newPonit = pointTime+"|"+pointType+"|"+ClockPointEnum.EQUAL.getKey()+"|"+flexibleWork;
}else if (betWeenTime > zddxfz){
newPonit = point +"|"+DateUtil.AfterMinutes(kssjStart,zddxfz);
flexibleWork = DateUtil.AfterMinutes(kssjStart,zddxfz);
}
clcokInTimeMap.remove(point);
clcokInTimeMap.put(newPonit,clcokInTime);
}
}else if (pointTime.equals(jssjEnd) && ClockPointEnum.END.getKey().equals(pointType) && clcokInTime != null){
//该卡点是弹性下班点
int betweenToWorkTime = DateUtil.getBetWeenMinutes(flexibleWork,kssjStart);
//弹性下班时间点
String flexibleOffWork = jssjEnd;
if (betweenToWorkTime >=0){
flexibleOffWork = DateUtil.beforeMinutes(flexibleOffWork,Math.abs(betweenToWorkTime));
}else if (betweenToWorkTime < 0){
flexibleOffWork = DateUtil.AfterMinutes(flexibleOffWork,Math.abs(betweenToWorkTime));
}
//根据弹性下班时间点重新计算
Map<String,Map<String,Object>> jsdkNearestClcokInTime = Utils.getNearestClcokInTimeCmd(flexibleOffWork,clockInTimeList);
String newtimeType = ClockPointEnum.EMPTY.getKey();
if (jsdkNearestClcokInTime.get(ClockPointEnum.EQUAL.getKey()) != null){
newtimeType=ClockPointEnum.EQUAL.getKey();
}
if (ClockPointEnum.EMPTY.getKey().equals(newtimeType) && jsdkNearestClcokInTime.get(ClockPointEnum.AFTER.getKey()) != null){
String clockInTime = jsdkNearestClcokInTime.get(ClockPointEnum.AFTER.getKey()).get("signdate") +" "+jsdkNearestClcokInTime.get(ClockPointEnum.AFTER.getKey()).get("signtime");
if (DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(DateUtil.AfterMinutes(flexibleOffWork,thdkfzs))) <=0){
newtimeType=ClockPointEnum.AFTER.getKey();
}
}
if (ClockPointEnum.EMPTY.getKey().equals(newtimeType) && jsdkNearestClcokInTime.get(ClockPointEnum.BEFORE.getKey()) != null){
String clockInTime = jsdkNearestClcokInTime.get(ClockPointEnum.BEFORE.getKey()).get("signdate") +" "+jsdkNearestClcokInTime.get(ClockPointEnum.BEFORE.getKey()).get("signtime");
if (DateUtil.getTime(clockInTime).compareTo(DateUtil.getTime(kssjEnd)) >0){
newtimeType=ClockPointEnum.BEFORE.getKey();
}
}
String newPonit = jssjEnd+"|"+ClockPointEnum.END.getKey()+"|"+newtimeType+"|"+flexibleOffWork;
clcokInTimeMap.remove(point);
clcokInTimeMap.put(newPonit,jsdkNearestClcokInTime.get(newtimeType));
}
}
}
}
}
//当有2笔需要打卡时可能会有打卡歧义的情况歧义情况取2个时间点的中间值当打卡时间小于中间值归属前一个打卡大于则相反
if (clcokInTimeData.size() >1){
for (int i=0;i<clcokInTimeData.size()-1;i++){
Map<String,Map<String,Object>> beforeClcokInTimeData = clcokInTimeData.get(i);
Map<String,Map<String,Object>> afterClcokInTimeData = clcokInTimeData.get(i+1);
Map<String,Object> beforeClcokInTimeMap = null;
String beforeClcokInTime = "";
String afterClcokInTime = "";
Map<String,Object> afterClcokInTimeMap = null;
for (Map.Entry<String,Map<String,Object>> beforeEntry :beforeClcokInTimeData.entrySet()){
beforeClcokInTimeMap = beforeEntry.getValue();
beforeClcokInTime = beforeEntry.getKey();
}
for (Map.Entry<String,Map<String,Object>> afterEntry :afterClcokInTimeData.entrySet()){
afterClcokInTimeMap = afterEntry.getValue();
afterClcokInTime = afterEntry.getKey();
}
//重复
if (beforeClcokInTimeMap != null && beforeClcokInTimeMap == afterClcokInTimeMap ){
String beforeTime = beforeClcokInTime.split("\\|")[0];
String afterTime = afterClcokInTime.split("\\|")[0];
long betWeenMinutes = DateUtil.getBetWeenMinutes(beforeTime,afterTime);
String middileTime = DateUtil.AfterMinutes(beforeTime,betWeenMinutes/2);
String signdateTime = beforeClcokInTimeMap.get("signdate") +" "+beforeClcokInTimeMap.get("signtime");
if (DateUtil.getTime(signdateTime).compareTo(DateUtil.getTime(middileTime)) <=0){
//该打卡归属前一个打卡点
afterClcokInTimeData.put(afterClcokInTime,null);
}else if (DateUtil.getTime(signdateTime).compareTo(DateUtil.getTime(middileTime)) >0){
//该打卡归属后一个打卡点
beforeClcokInTimeData.put(beforeClcokInTime,null);
}
}
}
}
return clcokInTimeData;
}
public static Map<String, Object> getNeedRecordClockInTime(List<Map<String,Map<String,Object>>> clcokInTimeData) {
Map<String, Object> resultMap = Maps.newHashMap();
int inIndex = 1;
int outIndex = 1;
for (Map<String,Map<String,Object>> clcokInTimeMap : clcokInTimeData){
//卡点
String point = "";
//当天打卡数据
Map<String,Object> clcokInTime = null;
for (Map.Entry<String,Map<String,Object>> entry :clcokInTimeMap.entrySet()){
point = entry.getKey();
clcokInTime = entry.getValue();
}
//需要计算的班次打卡时间点
String pointTime = point.split("\\|")[0];
//start开始打卡时间点end结束打卡时间点
String pointType = point.split("\\|")[1];
//empty:漏卡equal:打卡时间和班次时间相等before打卡时间在班次时间之前after打卡时间在班次时间之后
String timeType = point.split("\\|")[2];
if (ClockPointEnum.START.getKey().equals(pointType)){
//开始时间打卡
String key = "j"+inIndex;
if (!ClockPointEnum.EMPTY.getKey().equals(timeType) && clcokInTimeData != null){
String value = clcokInTime.get("signdate")+" "+clcokInTime.get("signtime");
resultMap.put(key,value);
}
inIndex++;
}else if (ClockPointEnum.END.getKey().equals(pointType)){
//结束时间打卡
String key = "c"+outIndex;
if (!ClockPointEnum.EMPTY.getKey().equals(timeType) && clcokInTimeData != null){
String value = clcokInTime.get("signdate")+" "+clcokInTime.get("signtime");
resultMap.put(key,value);
}
outIndex++;
}
}
return resultMap;
}
}