@ -4,15 +4,14 @@ import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service ;
import com.engine.jucailinkq.attendance.attendanceanalysis.service.UtilService ;
import com.engine.jucailinkq.attendance.attendanceanalysis.service.impl.UtilServiceImpl ;
import com.engine.jucailinkq.attendance.enums.AttendanceItemTypeEnum ;
import com.engine.jucailinkq.attendance.enums.ClassSegmentTypeEnum ;
import com.engine.jucailinkq.attendance.enums.DateTypeEnum ;
import com.engine.jucailinkq.attendance.enums.WorkForTimeEnum ;
import com.engine.jucailinkq.attendance.enums.* ;
import com.engine.jucailinkq.attendance.workflow.service.OvertimePlanService ;
import com.engine.jucailinkq.common.util.CommonUtil ;
import com.engine.jucailinkq.common.util.DateUtil ;
import com.engine.jucailinkq.common.util.DbTools ;
import com.engine.jucailinkq.common.util.Utils ;
import lombok.extern.slf4j.Slf4j ;
import weaver.general.TimeUtil ;
import weaver.general.Util ;
import java.util.* ;
@ -68,6 +67,8 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ
Map < String , String > dateToBcxxMap = scheduleInfoList = = null ? new HashMap < > ( ) : scheduleInfoList . stream ( ) . collect ( Collectors . toMap ( e - > Util . null2String ( e . get ( "bcrq" ) ) , e - > Util . null2String ( e . get ( "bcxx" ) ) ) ) ;
Map < String , String > dateTypeInfoFromBc = scheduleInfoList = = null ? new HashMap < > ( ) : scheduleInfoList . stream ( ) . collect ( Collectors . toMap ( e - > Util . null2String ( e . get ( "bcrq" ) ) , e - > Util . null2String ( e . get ( "rqlx" ) ) ) ) ;
existOvertimePlanList = existOvertimePlanInfo . get ( empId ) ;
Map < String , Double > weekOvertimeInfo = new HashMap < > ( ) ;
Map < String , Double > monthOvertimeInfo = new HashMap < > ( ) ;
for ( String date : dateList ) {
String realEndDate = date ;
detailItem = new HashMap < > ( ) ;
@ -76,8 +77,8 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ
detailItem . put ( "ksrq" , date ) ;
detailItem . put ( "kssj" , startTime ) ;
detailItem . put ( "jssj" , endTime ) ;
detailItem . put ( "jblx" , null ) ;
detailItem . put ( "jblxName" , null ) ;
detailItem . put ( "jblx" , "" ) ;
detailItem . put ( "jblxName" , "" ) ;
//开始时时和结束时间存在跨天情况时,即开始时间大于等于结束时间
if ( startTime . compareTo ( endTime ) > = 0 ) {
realEndDate = DateUtil . AfterDay ( date , 1 ) ;
@ -157,23 +158,23 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ
boolean currentDayOverLap = ! "" . equals ( currentDayStartToEnd ) & & DateUtil . isOverlapping ( date + " " + startTime , realEndDate + " " + endTime , currentDayStartTime , currentDayEndTime ) ;
boolean beforeDayOverLap = ! "" . equals ( beforeDayStartToEnd ) & & DateUtil . isOverlapping ( date + " " + startTime , realEndDate + " " + endTime , beforeDayStartTime , beforeDayEndTime ) ;
boolean nextDayOverLap = ! "" . equals ( nextDayStartToEnd ) & & DateUtil . isOverlapping ( date + " " + startTime , realEndDate + " " + endTime , nextDayStartTime , nextDayEndTime ) ;
//20240814需求变更。非休息班次, 出现重叠时间, 自动调整加班开始或结束时间, 并返回提示
Map < String , String > adjustInfo = new HashMap < > ( ) ;
adjustInfo . put ( "startWithAdjust" , date + " " + startTime ) ;
adjustInfo . put ( "endWithAdjust" , realEndDate + " " + endTime ) ;
if ( ( ! currentDayRestBc & & currentDayOverLap ) | | ( ! beforeDayRestBc & & beforeDayOverLap ) | | ( ! nextDayRestBc & & nextDayOverLap ) ) {
//20240814需求变更。非休息班次, 出现重叠时间, 自动调整加班开始或结束时间, 并返回提示
Map < String , String > adjustInfo = new HashMap < > ( ) ;
adjustInfo . put ( "startWithAdjust" , date + " " + startTime ) ;
adjustInfo . put ( "endWithAdjust" , realEndDate + " " + endTime ) ;
//处理前一天
if ( beforeDayOverLap ) {
if ( ! beforeDayRestBc & & beforeDayOverLap ) {
belongDate = DateUtil . beforeDay ( date , 1 ) ;
adjustInfo = doAdjust ( adjustInfo , beforeDayStartTime , beforeDayEndTime ) ;
}
//处理当天
if ( currentDayOverLap ) {
if ( ! currentDayRestBc & & currentDayOverLap ) {
belongDate = "" . equals ( belongDate ) ? date : belongDate ;
adjustInfo = doAdjust ( adjustInfo , currentDayStartTime , currentDayEndTime ) ;
}
//处理次日
if ( nextDayOverLap ) {
if ( ! nextDayRestBc & & nextDayOverLap ) {
belongDate = "" . equals ( belongDate ) ? DateUtil . AfterDay ( date , 1 ) : belongDate ;
adjustInfo = doAdjust ( adjustInfo , nextDayStartTime , nextDayEndTime ) ;
}
@ -183,19 +184,27 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ
detailItem . put ( "jssj" , adjustInfo . get ( "endTime" ) ) ;
detailItem . put ( "jsrq" , adjustInfo . get ( "endDate" ) ) ;
overtimeMinutes = DateUtil . getBetWeenMinutes ( adjustInfo . get ( "startWithAdjust" ) , adjustInfo . get ( "endWithAdjust" ) ) ;
detailItem . put ( "jbsc" , String . format ( "%.2f" , overtimeMinutes / 60.0 ) ) ;
//4-非休息班次,出现重叠时间,属于不合理加班安排,返回提示”已自动调整开始和结束时间点“
errorMessage . add ( Util . null2String ( empIdToNameInfo . get ( empId ) ) + "在日期" + date + "的加班计划区间和非休息班次班段出现时间重叠,已自动调整开始和结束时间点!" ) ;
//5-加班区间和休息班次出现重叠,首次重叠的日期,即为归属日期
} else if ( beforeDayRestBc & & beforeDayOverLap ) {
}
//5-加班区间和休息班次出现重叠,首次重叠的日期,即为归属日期;如果已有归属日,则比较当前日期和归属日谁更早
//20240816需求变更, 需要去除重叠的休息班次中的休息时段时长
int restOverLapMinutes = 0 ;
if ( beforeDayRestBc & & beforeDayOverLap ) {
belongDate = DateUtil . beforeDay ( date , 1 ) ;
restOverLapMinutes = restOverLapMinutes
+ countRestOverLapMinutes ( beforeDayBcId , adjustInfo . get ( "startWithAdjust" ) , adjustInfo . get ( "endWithAdjust" ) , DateUtil . beforeDay ( date , 1 ) ) ;
} else if ( currentDayRestBc & & currentDayOverLap ) {
belongDate = date ;
belongDate = "" . equals ( belongDate ) | | date . compareTo ( belongDate ) < 0 ? date : belongDate ;
restOverLapMinutes = restOverLapMinutes
+ countRestOverLapMinutes ( currentDayBcId , adjustInfo . get ( "startWithAdjust" ) , adjustInfo . get ( "endWithAdjust" ) , date ) ;
} else if ( nextDayRestBc & & nextDayOverLap ) {
belongDate = DateUtil . AfterDay ( date , 1 ) ;
belongDate = "" . equals ( belongDate ) ? DateUtil . AfterDay ( date , 1 ) : belongDate ;
restOverLapMinutes = restOverLapMinutes
+ countRestOverLapMinutes ( nextDayBcId , adjustInfo . get ( "startWithAdjust" ) , adjustInfo . get ( "endWithAdjust" ) , DateUtil . AfterDay ( date , 1 ) ) ;
}
overtimeMinutes = overtimeMinutes - restOverLapMinutes ;
detailItem . put ( "jbsc" , String . format ( "%.2f" , overtimeMinutes / 60.0 ) ) ;
}
//判断归属日的日期类型,首先从排班的信息来获取
String belongDateType = dateTypeInfoFromBc . getOrDefault ( belongDate , "" ) ;
@ -208,6 +217,7 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ
//获取人员在归属日被设置的考勤项目
List < Map < String , Object > > attendanceItemSetList = CommonUtil . getAttendanceItemsByEmpIdDate ( empId , belongDate ) ;
List < String > kqxmSetIds = attendanceItemSetList . stream ( ) . map ( f - > f . get ( "keyid" ) . toString ( ) ) . collect ( Collectors . toList ( ) ) ;
log . info ( Util . null2String ( empIdToNameInfo . get ( empId ) ) + "在日期" + date + "的可用考勤项目:" + kqxmSetIds ) ;
Map < String , Object > matchItemInfo = new HashMap < > ( ) ;
for ( Map < String , Object > attendanceItemInfo : jblxAttendanceList ) {
//判断该加班类型考勤项目是否被该人员使用,且考勤项目的绑定的日期类型是否包含归属日期类型
@ -221,9 +231,11 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ
detailItem . put ( "gsrq" , belongDate ) ;
//20240814需求变更。增加单条明细的最小加班分钟数校验, 工作日加班最大小时数、周加班最大小时数、月加班最大小时数
if ( matchItemInfo . size ( ) = = 0 ) {
log . info ( Util . null2String ( empIdToNameInfo . get ( empId ) ) + "在日期" + date + "的加班计划未匹配到合适的加班类型!" ) ;
errorMessage . add ( Util . null2String ( empIdToNameInfo . get ( empId ) ) + "在日期" + date + "的加班计划未匹配到合适的加班类型!" ) ;
continue ;
} else {
log . info ( Util . null2String ( empIdToNameInfo . get ( empId ) ) + "在日期" + date + "的加班计划匹配到:" + Util . null2String ( matchItemInfo . get ( "mc" ) ) ) ;
String minMinutes = Util . null2String ( matchItemInfo . get ( "jbqsfzs" ) ) ;
if ( ! "" . equals ( minMinutes ) & & Integer . parseInt ( minMinutes ) > overtimeMinutes ) {
//最小加班分钟数大于单条明细的加班时长分钟数
@ -236,21 +248,61 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ
String limitWorkDayHours = Util . null2String ( matchItemInfo . get ( "rzdjbxss" ) ) ;
String limitWeekHours = Util . null2String ( matchItemInfo . get ( "zzdjbxss" ) ) ;
String limitMonthHours = Util . null2String ( matchItemInfo . get ( "yzdjbxss" ) ) ;
String limitDealType = Util . null2String ( matchItemInfo . get ( "ccclfs" ) ) ;
boolean doLimitWorkDayHours = false ;
boolean doLimitWeekHours = false ;
boolean doLimitMonthHours = false ;
//判断是否满足工作日加班最大小时数
boolean needCheckWorkDayHours = ! "" . equals ( limitWorkDayHours ) & & ( belongDateType . equals ( DateTypeEnum . WORK_DAY . getKey ( ) ) | | belongDateType . equals ( DateTypeEnum . CHANGECLASS . getKey ( ) ) ) ;
if ( needCheckWorkDayHours & & Double . compare ( Double . parseDouble ( limitWorkDayHours ) , overtimeMinutes / 60.0 ) < 0 ) {
errorMessage . add ( Util . null2String ( empIdToNameInfo . get ( empId ) ) + "在日期" + date + "的加班时长加班类型-"
doLimitWorkDayHours = true ;
errorMessage . add ( Util . null2String ( empIdToNameInfo . get ( empId ) ) + "在日期" + date + "的加班时长累计后超过了加班类型-"
+ Util . null2String ( matchItemInfo . get ( "mc" ) ) + "设置的工作日加班最大小时数!" ) ;
continue ;
}
//判断是否满足周加班最大小时数
if ( ! "" . equals ( limitWeekHours ) ) {
int weekRank = DateUtil . weekRank ( belongDate ) ;
double maxWeekMinutes = Double . parseDouble ( limitWeekHours ) * 60 ;
double weekOvertimeMinutes ;
if ( weekOvertimeInfo . get ( belongDate . split ( "-" ) [ 0 ] + "" + weekRank ) = = null ) {
String countStartDate = DateUtil . beforeDay ( belongDate . split ( "-" ) [ 0 ] + "-" + belongDate . split ( "-" ) [ 1 ] + "-01" , 6 ) ;
String countEndDate = DateUtil . AfterDay ( belongDate . split ( "-" ) [ 0 ] + "-" + belongDate . split ( "-" ) [ 1 ] + "-28" , 9 ) ;
weekOvertimeMinutes = getWeekTimeMinutes ( getWorkOverTimeResults ( countStartDate , countEndDate , empId ) , belongDate ) ;
} else {
weekOvertimeMinutes = weekOvertimeInfo . get ( belongDate . split ( "-" ) [ 0 ] + "" + weekRank ) ;
}
weekOvertimeInfo . put ( belongDate . split ( "-" ) [ 0 ] + "" + weekRank , weekOvertimeMinutes + overtimeMinutes ) ;
if ( maxWeekMinutes - weekOvertimeMinutes - overtimeMinutes < 0 ) {
//达到周加班最大小时数
doLimitWeekHours = true ;
errorMessage . add ( Util . null2String ( empIdToNameInfo . get ( empId ) ) + "在日期" + date + "的加班时长累计后超过了加班类型-"
+ Util . null2String ( matchItemInfo . get ( "mc" ) ) + "设置的周加班最大小时数!" ) ;
}
}
//判断是否满足月加班最大小时数
if ( ! "" . equals ( limitMonthHours ) ) {
String yearMonth = belongDate . substring ( 0 , 7 ) ;
double maxMonthMinutes = Double . parseDouble ( limitMonthHours ) * 60 ;
double monthOvertimeMinutes ;
if ( monthOvertimeInfo . get ( yearMonth ) = = null ) {
String countStartDate = belongDate . split ( "-" ) [ 0 ] + "-" + belongDate . split ( "-" ) [ 1 ] + "-01" ;
String countEndDate = belongDate . split ( "-" ) [ 0 ] + "-" + belongDate . split ( "-" ) [ 1 ] + "-31" ;
monthOvertimeMinutes = getMonthTimeMinutes ( getWorkOverTimeResults ( countStartDate , countEndDate , empId ) , belongDate ) ;
} else {
monthOvertimeMinutes = monthOvertimeInfo . get ( yearMonth ) ;
}
monthOvertimeInfo . put ( yearMonth , monthOvertimeMinutes + overtimeMinutes ) ;
if ( maxMonthMinutes - monthOvertimeMinutes - overtimeMinutes < 0 ) {
//达到月加班最大小时数
doLimitMonthHours = true ;
errorMessage . add ( Util . null2String ( empIdToNameInfo . get ( empId ) ) + "在日期" + date + "的加班时长累计后超过了加班类型-"
+ Util . null2String ( matchItemInfo . get ( "mc" ) ) + "设置的月加班最大小时数!" ) ;
}
}
// //判断是否超出工作日、周、月最大小时数要求
// if ("1".equals(limitDealType) && (doLimitWorkDayHours || doLimitWeekHours || doLimitMonthHours)) {
// continue;
// }
}
}
overtimePlanDetailList . add ( detailItem ) ;
@ -258,12 +310,11 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ
}
if ( errorMessage . size ( ) = = 0 ) {
resultMap . put ( "status" , true ) ;
resultMap . put ( "data" , overtimePlanDetailList ) ;
} else {
resultMap . put ( "status" , false ) ;
resultMap . put ( "errorInfo" , errorMessage ) ;
resultMap . put ( "data" , null ) ;
}
resultMap . put ( "data" , overtimePlanDetailList ) ;
} catch ( Exception e ) {
log . info ( e . getMessage ( ) ) ;
@ -274,6 +325,21 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ
return resultMap ;
}
/ * *
* 目 标 区 间 和 日 期 所 在 班 次 的 休 息 时 段 重 叠 的 分 钟 数
* /
private int countRestOverLapMinutes ( String nextDayBcId , String startTime , String endTime , String date ) {
List < String > countBdlxList = new ArrayList < > ( ) ;
countBdlxList . add ( ClassSegmentTypeEnum . REST_AND_DINE . getKey ( ) ) ;
countBdlxList . add ( ClassSegmentTypeEnum . REST_PERIOD . getKey ( ) ) ;
countBdlxList . add ( ClassSegmentTypeEnum . DINING_PERIOD . getKey ( ) ) ;
String sql = "select id, bdlx, gsrq, kssj as dtkssj, jssj as dtjssj from uf_jcl_kq_bcxx_dt1 where mainid = " + nextDayBcId ;
List < Map < String , Object > > bcDetailData = DbTools . getSqlToList ( sql ) ;
bcDetailData = bcDetailData . stream ( ) . filter ( e - > countBdlxList . contains ( Util . null2String ( e . get ( "bdlx" ) ) ) ) . collect ( Collectors . toList ( ) ) ;
//获取需要累计的班段时长区间和目标区间存在交集的分钟数
return Utils . removeTime ( startTime , endTime , bcDetailData , date ) ;
}
private Map < String , String > doAdjust ( Map < String , String > adjustInfo , String bcStartTime , String bcEndTime ) {
String startWithAdjust = adjustInfo . get ( "startWithAdjust" ) ;
String endWithAdjust = adjustInfo . get ( "endWithAdjust" ) ;
@ -366,4 +432,63 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ
}
return startToEnd ;
}
/ * *
* 获 得 一 周 加 班 分 钟 数
* @param dataList
* @return
* /
public double getWeekTimeMinutes ( List < Map < String , Object > > dataList , String date ) {
int day = TimeUtil . getDayOfWeek ( date ) ;
if ( day = = 0 ) {
day = 7 ;
}
String startDate = DateUtil . beforeDay ( date , day - 1 ) ;
String endDate = DateUtil . AfterDay ( date , 7 - day ) ;
List < Map < String , Object > > list = dataList . stream ( ) . filter ( e - > {
String sjksrq = Util . null2String ( e . get ( "sjksrq" ) ) ;
if ( DateUtil . getTime ( sjksrq ) . compareTo ( DateUtil . getTime ( startDate ) ) > = 0 & &
DateUtil . getTime ( sjksrq ) . compareTo ( DateUtil . getTime ( endDate ) ) < = 0 & &
DateUtil . getTime ( sjksrq ) . compareTo ( DateUtil . getTime ( date ) ) ! = 0 ) {
return true ;
} else {
return false ;
}
} ) . collect ( Collectors . toList ( ) ) ;
double totalMinutes = 0 ;
for ( Map < String , Object > data : list ) {
String hsdw = data . get ( "hsdw" ) . toString ( ) ;
totalMinutes + = Utils . getItemduration ( 1 , AccountingUnitEnum . MINUTES . getKey ( ) , Double . valueOf ( data . get ( "sjjbsc" ) . toString ( ) ) , AccountingUnitEnum . getEnum ( hsdw ) , 8 ) ;
}
return totalMinutes ;
}
/ * *
* 获 得 一 个 月 加 班 分 钟 数
* @param dataList
* @return
* /
public double getMonthTimeMinutes ( List < Map < String , Object > > dataList , String date ) {
String startDate = date . split ( "-" ) [ 0 ] + "-" + date . split ( "-" ) [ 1 ] + "-01" ;
String endDate = date . split ( "-" ) [ 0 ] + "-" + date . split ( "-" ) [ 1 ] + "-31" ;
List < Map < String , Object > > list = dataList . stream ( ) . filter ( e - > DateUtil . getTime ( e . get ( "sjksrq" ) . toString ( ) ) . compareTo ( DateUtil . getTime ( startDate ) ) > = 0 & &
DateUtil . getTime ( e . get ( "sjjsrq" ) . toString ( ) ) . compareTo ( DateUtil . getTime ( endDate ) ) < = 0 ) . collect ( Collectors . toList ( ) ) ;
double totalMinutes = 0 ;
for ( Map < String , Object > data : list ) {
String hsdw = data . get ( "hsdw" ) . toString ( ) ;
totalMinutes + = Utils . getItemduration ( 1 , AccountingUnitEnum . MINUTES . getKey ( ) , Double . valueOf ( data . get ( "sjjbsc" ) . toString ( ) ) , AccountingUnitEnum . getEnum ( hsdw ) , 8 ) ;
}
return totalMinutes ;
}
/ * *
* 获 取 目 标 人 员 时 间 区 间 内 的 加 班 结 果
* /
public List < Map < String , Object > > getWorkOverTimeResults ( String startDate , String endDate , String userId ) {
String sql = "select a.sjjbsc, a.sjksrq, a.sjjsrq, a.jblx, b.hsdw from uf_jcl_kq_jbjg a left join uf_jcl_kq_kqxm b on a.jblx = b.id where a.jbry=? and a.sjksrq>=? and a.sjjsrq<=?" ;
List < Map < String , Object > > dataList = DbTools . getSqlToList ( sql , userId , startDate , endDate ) ;
return dataList ;
}
}