package com.yonyou.hrcloud.attentrpt.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yonyou.hrcloud.adder.exception.AdderBusinessException;
import com.yonyou.hrcloud.adder.model.param.Sorter;
import com.yonyou.hrcloud.adder.model.query.ChainLogicExpression;
import com.yonyou.hrcloud.adder.model.query.Condition;
import com.yonyou.hrcloud.adder.model.query.LogicExpression;
import com.yonyou.hrcloud.adder.model.query.Operator;
import com.yonyou.hrcloud.adder.model.query.ValueExpression;
import com.yonyou.hrcloud.adder.service.IGenericService;
import com.yonyou.hrcloud.attend.helper.IAttendConst;
import com.yonyou.hrcloud.attend.helper.MultilingualTranslateHelper;
import com.yonyou.hrcloud.attend.model.AttendPeriod;
import com.yonyou.hrcloud.attend.model.AttendSchemeVO;
import com.yonyou.hrcloud.attend.model.AttendStaff;
import com.yonyou.hrcloud.attend.model.Shift;
import com.yonyou.hrcloud.attend.model.TsAttendRuleVO;
import com.yonyou.hrcloud.attend.service.IAttendPeriodService;
import com.yonyou.hrcloud.attend.service.IAttendRuleService;
import com.yonyou.hrcloud.attend.service.IAttendStaffService;
import com.yonyou.hrcloud.attend.service.IShiftService;
import com.yonyou.hrcloud.attendrptnew.dataset.DataSetConstant;
import com.yonyou.hrcloud.attendrptnew.impl.AttendDataDateHelperServiceImpl;
import com.yonyou.hrcloud.attentrpt.dao.IAttendRptCalDao;
import com.yonyou.hrcloud.attentrpt.helper.utils.ElasticShiftaAttendUtils;
import com.yonyou.hrcloud.attentrpt.model.AttendDayRptVO;
import com.yonyou.hrcloud.attentrpt.model.AttendMonthRptVO;
import com.yonyou.hrcloud.attentrpt.model.AttendRptParams;
import com.yonyou.hrcloud.attentrpt.model.AttendTodayRptVO;
import com.yonyou.hrcloud.attentrpt.service.IAttendDataService;
import com.yonyou.hrcloud.attentrpt.service.ITsAttendRptCoreBusinessService;
import com.yonyou.hrcloud.attentrpt.service.ITsAttendRptService;
import com.yonyou.hrcloud.berry.helper.DateStyle;
import com.yonyou.hrcloud.berry.helper.DateUtil;
import com.yonyou.hrcloud.berry.helper.HRCloudConst;
import com.yonyou.hrcloud.businesstrip.model.BusinessTripApplyDetail;
import com.yonyou.hrcloud.calendar.service.IAttendCalendarService;
import com.yonyou.hrcloud.holiday.model.Holiday;
import com.yonyou.hrcloud.holiday.model.WorkingCalendar;
import com.yonyou.hrcloud.holiday.service.IHolidayService;
import com.yonyou.hrcloud.leave.model.LeaveApplyDetail;
import com.yonyou.hrcloud.leave.model.LeaveTypeNew;
import com.yonyou.hrcloud.leave.service.ILeaveApplyService;
import com.yonyou.hrcloud.leave.service.ILeaveTypeNewService;
import com.yonyou.hrcloud.overtime.helper.OvertimeTypeEnum;
import com.yonyou.hrcloud.overtime.model.OvertimeRule;
import com.yonyou.hrcloud.overtime.model.OvertimeSplitBillVO;
import com.yonyou.hrcloud.overtime.service.IOvertimeRuleService;
import com.yonyou.hrcloud.sign.model.AttendRecord;
import com.yonyou.hrcloud.sign.service.IAttendCommonService;
import com.yonyou.hrcloud.support.MqMsgSupport;
import com.yonyou.hrcloud.tcommon.helper.AttendStaffHelper;
import com.yonyou.hrcloud.tcommon.model.AttendData;
import com.yonyou.hrcloud.tcommon.model.DefaultTimeScope;
import com.yonyou.hrcloud.tcommon.model.ITimeScope;
import com.yonyou.hrcloud.tcommon.model.TimeConst;
import com.yonyou.hrcloud.tcommon.service.ItimeCommonService;
import com.yonyou.hrcloud.tcommon.utils.DataFilterUtils;
import com.yonyou.hrcloud.tcommon.utils.ElasticShiftUtils;
import com.yonyou.hrcloud.tcommon.utils.MultiLangHelper;
import com.yonyou.hrcloud.tcommon.utils.TimePubUtils;
import com.yonyou.hrcloud.tcommon.utils.TimeScopeUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@Transactional
@Scope("prototype")
public class TsAttendRptCoreBusinessServiceImpl implements ITsAttendRptCoreBusinessService {
    @Autowired
    IShiftService shiftservice;
    @Autowired
    IAttendStaffService attendStaffService;
    @Autowired
    IAttendCalendarService calendarService;
    @Autowired
    @Lazy
    ITsAttendRptService rptService;
    @Autowired
    IAttendPeriodService periodService;
    @Autowired
    IAttendRptCalDao iAttendRptCalDao;
    @Autowired
    IHolidayService holidayService;
    @Autowired
    public ILeaveTypeNewService leaveTypeNewService;
    @Autowired
    IAttendDataService attendDataService;
    @Autowired
    ILeaveApplyService iLeaveApplyService;
    @Autowired
    public IAttendRuleService ruleService;
    @Autowired
    public IAttendCommonService attendCommonService;
    @Autowired
    private ItimeCommonService itimeCommonService;

    @Autowired
    private IGenericService iGenericService;
    @Lazy
    @Autowired
    public IOvertimeRuleService otruleService;

    @Resource
    private AttendDataDateHelperServiceImpl attendDataDateHelperService;

    /**
     * 如果日期范围有考勤日报数据就直接返回，如果没有也返回rptvo 里面只有基础信息staffid 日期这些
     */
    public List<AttendDayRptVO> queryRpt4Cal(String[] staff_ids, Date beginDate, Date endDate, boolean isTask) {
        beginDate = DateUtil.StringToDate(DateUtil.DateToString(beginDate, DateStyle.YYYY_MM_DD));
        endDate = DateUtil.StringToDate(DateUtil.DateToString(endDate, DateStyle.YYYY_MM_DD));
        //高级版和初级版都有考勤档案，现在不区分
        return queryRptSenior4Cal(isTask ? null : staff_ids, beginDate, endDate);
    }

    /**
     * 如果日期范围有考勤日报数据就直接返回，如果没有也返回rptvo 里面只有基础信息staffid 日期这些
     */
    public List<AttendDayRptVO> queryRpt4Cal(String[] staff_ids, Date beginDate, Date endDate, boolean isTask,List<AttendStaff> attendStaffList) {
        beginDate = DateUtil.StringToDate(DateUtil.DateToString(beginDate, DateStyle.YYYY_MM_DD));
        endDate = DateUtil.StringToDate(DateUtil.DateToString(endDate, DateStyle.YYYY_MM_DD));
        //高级版和初级版都有考勤档案，现在不区分
        return queryRptSenior4Cal(isTask ? null : staff_ids, beginDate, endDate,attendStaffList);
    }

    /***
     * 查询当天需要生成临时日报数据
     * 需要排除掉已经生成的人员
     * @param staff_ids
     * @param beginDate
     * @return
     */
    @Override
    public List<AttendTodayRptVO> queryRpt4CalToday(String[] staff_ids, Date beginDate) {
        List<AttendTodayRptVO> attendTodayRptVOList = new ArrayList<>();
        // 查当前日期范围内的考勤档案
        List<AttendStaff> attendStaffList = attendStaffService.queryAttend4Rpt(staff_ids, beginDate, beginDate);
        //对考勤档案进行结果循环
        if(CollectionUtils.isEmpty(attendStaffList)) return attendTodayRptVOList;
        for (AttendStaff attendStaff : attendStaffList) {
            AttendTodayRptVO todayRptVO = new AttendTodayRptVO();
            todayRptVO.setStaffId(attendStaff.getStaffId());
            todayRptVO.setOrgId(attendStaff.getOrgId());
            todayRptVO.setJobId(attendStaff.getStaffjobId());
            todayRptVO.setStaffName(attendStaff.getStaffName());
            todayRptVO.setCalendar(beginDate);
            attendTodayRptVOList.add(todayRptVO);
        }
        return attendTodayRptVOList;
    }

    /**
     * 如果日期范围有考勤日报数据就直接返回，如果没有也返回rptvo 里面只有基础信息staffid 日期这些
     * 考勤日报计算高级版本逻辑
     * 1、以日期为单位
     */
    private List<AttendDayRptVO> queryRptSenior4Cal(String[] staff_ids, Date beginDate, Date endDate,List<AttendStaff> attendStaffList) {
        beginDate = DateUtil.StringToDate(DateUtil.DateToString(beginDate, DateStyle.YYYY_MM_DD));
        endDate = DateUtil.StringToDate(DateUtil.DateToString(endDate, DateStyle.YYYY_MM_DD));
        // 查当前日期范围内的考勤档案
        Map<String, AttendStaff> attendStaffMap;
        if(CollectionUtils.isNotEmpty(attendStaffList)){
            attendStaffMap = AttendStaffHelper.getAttendStaffMapByDate(attendStaffList,beginDate,endDate);
        }else{
            attendStaffMap = attendStaffService.queryAttendStaffForRpt(staff_ids, beginDate, endDate);
        }
        // 查询当前日期范围内的考勤日报数据
        Condition rptCond = new Condition();
        rptCond.addExpression("calendar", beginDate, Operator.GREATEREQUAL);
        rptCond.addExpression("calendar", endDate, Operator.LESSEQAUL);

        //定时任务全部，staff_ids为空
        if (ArrayUtils.isNotEmpty(staff_ids)) {
            rptCond.addExpression("staff_id", staff_ids, "in");
        }

        List<AttendDayRptVO> rptVos = rptService.queryAttendDayRptVOLit(rptCond, null);
        // 将rptVO 按staffid 分组
        Map<String, Map<String, AttendDayRptVO>> rptMap = getRptMap(rptVos);
        List<AttendDayRptVO> resultVo = new ArrayList<>();

        //对考勤档案进行结果循环，不用在对日期进行循环了
        if (attendStaffMap != null && attendStaffMap.size() > 0) {
            Set<String> keySet = attendStaffMap.keySet();
            Iterator<String> it = keySet.iterator();
            while (it.hasNext()) {
                String key = it.next();
                AttendStaff attendStaff = attendStaffMap.get(key);
                if (TimeConst.ATTEND_TYPE_NO.equals(attendStaff.getAttendType())) {// 不考勤的不管
                    continue;
                }
                String[] staffIDAndDate = key.split("@");
                String staffid = staffIDAndDate[0];
                String date = staffIDAndDate[1];
                Map<String, AttendDayRptVO> dateRptMap = null;
                if (null != rptMap) {
                    dateRptMap = rptMap.get(staffid);
                }

                AttendDayRptVO rptvo = null;
                // 如果已经有日报了
                if (null != dateRptMap && dateRptMap.containsKey(date)) {
                    rptvo = dateRptMap.get(date);
                    //数据库存在月报没审核，日报审核的数据，应该是弃审月报逻辑问题？
                    if(rptvo.getIsapprove() == null){
                        rptvo.setIsapprove(false);
                        rptvo.setDeptId(attendStaff.getDeptId());
                        rptvo.setOrgId(attendStaff.getOrgId());
                        rptvo.setJobId(attendStaff.getStaffjobId());
                    }
                    resultVo.add(rptvo);
                    continue;
                } else {// 没有new 一个只包含staff_id这些基础字段的
                    rptvo = new AttendDayRptVO();
                    rptvo.setStaffId(staffid);
                    rptvo.setOrgId(attendStaff.getOrgId());
                    rptvo.setJobId(attendStaff.getStaffjobId());
                    //这几个名字需要后面在处理
                    rptvo.setStaffName(attendStaff.getStaffName());
                    rptvo.setOrgName(attendStaff.getOrgName());
                    rptvo.setDeptId(attendStaff.getDeptId());
                    rptvo.setDeptName(attendStaff.getDeptName());
                    rptvo.setCorpName(attendStaff.getOrgName());
                    rptvo.setIsapprove(false);
                    rptvo.setCalendar(DateUtil.StringToDate(date, DateStyle.YYYY_MM_DD));
                    resultVo.add(rptvo);
                }
            }
        }
        return resultVo;
    }

    /**
     * 如果日期范围有考勤日报数据就直接返回，如果没有也返回rptvo 里面只有基础信息staffid 日期这些
     * 考勤日报计算高级版本逻辑
     * 1、以日期为单位
     */
    private List<AttendDayRptVO> queryRptSenior4Cal(String[] staff_ids, Date beginDate, Date endDate) {
        beginDate = DateUtil.StringToDate(DateUtil.DateToString(beginDate, DateStyle.YYYY_MM_DD));
        endDate = DateUtil.StringToDate(DateUtil.DateToString(endDate, DateStyle.YYYY_MM_DD));
        // 查当前日期范围内的考勤档案
        Map<String, AttendStaff> attendStaffMap = attendStaffService.queryAttendStaffForRpt(staff_ids, beginDate, endDate);
        // 查询当前日期范围内的考勤日报数据
        Condition rptCond = new Condition();
        rptCond.addExpression("calendar", beginDate, ">=");
        rptCond.addExpression("calendar", endDate, "<=");

        //定时任务全部，staff_ids为空
        if (staff_ids != null && staff_ids.length > 0) {
            rptCond.addExpression("staff_id", staff_ids, "in");
        }


        Sorter sorter = new Sorter("staff_id");
        List<AttendDayRptVO> rptVos = rptService.queryAttendDayRptVOLit(rptCond, sorter);
        // 将rptVO 按staffid 分组

        //String beginmonth = DateUtil.DateToString(beginDate, DateStyle.YYYYMM);
        //String endmonth = DateUtil.DateToString(endDate, DateStyle.YYYYMM);
        String beginmonth = getYearMonth(beginDate);
        String endmonth = getYearMonth(endDate);
        List<String> listApproveMonth = iAttendRptCalDao.queryApproveMonthRptInfo(staff_ids == null ? null : Arrays.asList(staff_ids), beginmonth, endmonth);
        Map<String, Map<String, AttendDayRptVO>> rptMap = getRptMap(rptVos);
//        Date[] dates = TimePubUtils.createDateArray(beginDate, endDate);
        List<AttendDayRptVO> resultVo = new ArrayList<>();

        //对考勤档案进行结果循环，不用在对日期进行循环了
        if (attendStaffMap != null && attendStaffMap.size() > 0) {
            Set<String> keySet = attendStaffMap.keySet();
            Iterator<String> it = keySet.iterator();
            while (it.hasNext()) {
                String key = it.next();
                AttendStaff attendStaff = attendStaffMap.get(key);
                if (TimeConst.ATTEND_TYPE_NO.equals(attendStaff.getAttendType())) {// 不考勤的不管
                    continue;
                }
                String[] staffIDAndDate = key.split("@");
                String staffid = staffIDAndDate[0];
                String date = staffIDAndDate[1];
                Date calendarDate = DateUtil.StringToDate(date, DateStyle.YYYY_MM_DD);
                String yyyyMM = getYearMonth(calendarDate);//DateUtil.DateToString(calendarDate, DateStyle.YYYYMM);
                boolean isapprove = false;
                if (listApproveMonth != null) {
                    //已审批
                    if (listApproveMonth.contains(staffid + yyyyMM)) {
                        isapprove = true;
                    }
                }
                Map<String, AttendDayRptVO> dateRptMap = null;
                if (null != rptMap) {
                    dateRptMap = rptMap.get(staffid);
                }

                AttendDayRptVO rptvo = null;
                if (null != dateRptMap && dateRptMap.containsKey(date)) {// 如果已经有日报了
                    rptvo = dateRptMap.get(date);
                    //数据库存在月报没审核，日报审核的数据，应该是弃审月报逻辑问题？
                    //后续优化时，考虑只根据日报状态判断就可以了
                    //另外还有范围，也要重新看下
                    //rptvo.setIsapprove(isapprove);
                    if(isapprove){
                        rptvo.setIsapprove(true);
                    }
                    else if(rptvo.getIsapprove() == null){
                        rptvo.setIsapprove(false);
                    }
                    rptvo.setDeptId(attendStaff.getDeptId());
                    rptvo.setOrgId(attendStaff.getOrgId());
                    rptvo.setJobId(attendStaff.getStaffjobId());
                    resultVo.add(rptvo);
                    continue;
                } else {// 没有new 一个只包含staff_id这些基础字段的
                    rptvo = new AttendDayRptVO();
                    rptvo.setStaffId(staffid);
                    rptvo.setOrgId(attendStaff.getOrgId());
                    rptvo.setJobId(attendStaff.getStaffjobId());
                    //这几个名字需要后面在处理
                    rptvo.setStaffName(attendStaff.getStaffName());
                    rptvo.setOrgName(attendStaff.getOrgName());
                    rptvo.setDeptName(attendStaff.getDeptName());
                    rptvo.setCorpName(attendStaff.getOrgName());
                    rptvo.setIsapprove(isapprove);
                    rptvo.setCalendar(calendarDate);
                    rptvo.setDeptId(attendStaff.getDeptId());
                    resultVo.add(rptvo);
                }
            }
        }
        return resultVo;
    }

    private static String getYearMonth(Date dt) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(dt);
        return String.format("%s%s",cal.get(Calendar.YEAR),cal.get(Calendar.MONTH) + 1);
    }

    private Map<String, Map<String, AttendDayRptVO>> getRptMap(List<AttendDayRptVO> rptVos) {
        if (CollectionUtils.isEmpty(rptVos))
            return null;
        Map<String, Map<String, AttendDayRptVO>> result = new HashMap<>();
        Map<String, AttendDayRptVO> dateRptMap = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (AttendDayRptVO rpt : rptVos) {
            if (!result.containsKey(rpt.getStaffId())) {
                dateRptMap = new HashMap<>();
                result.put(rpt.getStaffId(), dateRptMap);
            }else {
                dateRptMap=result.get(rpt.getStaffId());
            }
            dateRptMap.put(sdf.format(rpt.getCalendar()), rpt);
        }
        return result;
    }
    @Override
    @Transactional
    public Map<String, Map<String, Map<String, Map<String, Object>>>> queryAttendData(String[] staff_ids, Date beginDate, Date endDate, AttendSchemeVO attendSchemeVO, Map<String, Shift> shiftMap, boolean isTask,List<AttendStaff> attendStaffList,String logId){
        List<AttendData> dataList = null;
        try {
            dataList = attendDataService.getAttendData(beginDate, endDate, staff_ids, attendSchemeVO, shiftMap, isTask,attendStaffList);
        } catch (Exception e) {
            MqMsgSupport.logMsg(logId,"-------生成考勤数据时失败---------"+e.getMessage());
            log.error(String.format("生成考勤数据时失败-%s",e.getMessage()),e);
            throw new AdderBusinessException("生成考勤数据时失败{0}", "attend.report.i18n45", e.getMessage());
        }

        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        Map<String, Map<String, Map<String, Map<String, Object>>>> resultMap = new HashMap<>();
        Map<String, Map<String, Map<String, Object>>> attendDataMap = new HashMap<>();//考勤数据
        Map<String, Map<String, Map<String, Object>>> extDataMap = new HashMap<>();//业务单据类型数据
        Map<String, Map<String, Object>> calMap = new HashMap<>();
        Map<String, Map<String, Object>> typeDataMap = new HashMap<>();
        String staff_id = "";
        // 查出班次ID map赋值班次名称用
        for (AttendData data : dataList) {
            if (null != staff_id && !staff_id.equals(data.getStaffId())) {
                calMap = new HashMap<>();
                typeDataMap = new HashMap<>();
            }
            staff_id = data.getStaffId();
            Map<String, Object> valueMap = new HashMap<>();
            String calendar = DateUtil.DateToString(data.getCalendar(), DateStyle.YYYY_MM_DD);
            valueMap.put(AttendData.CALENDAR, calendar);//日期
            valueMap.put(AttendData.ACTUALWORKHOURS, data.getActualworkhours());
            valueMap.put(AttendData.ACTUALWORKDAYS, data.getActualworkdays());
            valueMap.put(AttendData.WORKHOURS, data.getWorkhours());
            valueMap.put(AttendData.WORKDAYS, data.getWorkdays());
            valueMap.put(AttendData.UNNORMALLEN, data.getUnnormallen());
            valueMap.put(AttendData.LATELONG, data.getLatelong());
            valueMap.put(AttendData.EARLYLONG, data.getEarlylong());
            valueMap.put(AttendData.ABSENTHOUR, data.getAbsenthour());
            valueMap.put(AttendData.LATECOUNT, data.getLatecount());
            valueMap.put(AttendData.EARLYCOUNT, data.getEarlycount());
            valueMap.put(AttendData.RESIGNCNT, data.getResigncnt());
            valueMap.put(AttendData.ISABSENT, data.isIsabsent() ? 1 : 0);
            valueMap.put(AttendData.ABSENTCOUNT, data.getAbsentcount());
            valueMap.put(AttendData.ISNORMAL, data.isIsnormal());
            valueMap.put(AttendData.ISHOLIDAY, data.isIsholiday());
            valueMap.put(AttendData.BILLSTATEPASS, data.getBillStatePass());

            valueMap.put(AttendData.SIGNBEGINTIME, data.getSignbegintime());
            valueMap.put(AttendData.SIGNENDTIME, data.getSignendtime());
            valueMap.put(AttendData.SHIFT_ID, data.getShiftId());

            valueMap.put(AttendData.FIRSTBEGINSIGN, data.getFirstBeginsign());
            valueMap.put(AttendData.FIRSTBEGINSIGNSTATUS, data.getFirstBeginsignStatus());
            valueMap.put(AttendData.FIRSTENDSIGN, data.getFirstEndsign());
            valueMap.put(AttendData.FIRSTENDSIGNSTATUS, data.getFirstEndsignStatus());

            valueMap.put(AttendData.SECONDBEGINSIGN, data.getSecondBeginsign());
            valueMap.put(AttendData.SECONDBEGINSIGNSTATUS, data.getSecondBeginsignStatus());
            valueMap.put(AttendData.SECONDENDSIGN, data.getSecondEndsign());
            valueMap.put(AttendData.SECONDENDSIGNSTATUS, data.getSecondEndsignStatus());


            valueMap.put(AttendData.ISLEAVE, data.isIsleave());
            valueMap.put(AttendData.LEAVECNT, data.getLeavecnt());
            valueMap.put(AttendData.TRIPCNT, data.getTripcnt());
            valueMap.put(AttendData.RULEID, data.getRuleid());
            valueMap.put(AttendData.NOBRUSHCOUNT, data.getNobrushcount());
            valueMap.put(AttendData.UNNORMALCOUNT, data.getUnnormalcount());
            valueMap.put(AttendData.ISFULLDUTY, data.getIsfullduty());
            valueMap.put(AttendData.OUTSIDECOUNT, data.getOutsidecount());
            valueMap.put(AttendData.ISOUTSIDE, data.isIsoutside());
            valueMap.put("countrycode", data.getCountrycode());//国家编码
            valueMap.put(AttendData.DATETYPE, data.getDateType());//日期类型

            if (!StringUtils.isEmpty(data.getShiftId())) {
                Shift shift = shiftMap.get(data.getShiftId());
                if (shift == null) {
                    valueMap.put(AttendData.SHIFT_NAME, MultilingualTranslateHelper.getRest());
                } else {
                    valueMap.put(AttendData.SHIFT_NAME, Shift.getLangShiftName(shift));
                    valueMap.put(AttendData.SHIFTBEGINTIME, shift.getBegintime());
                    valueMap.put(AttendData.SHIFTENDTIME, shift.getEndtime());
                }
            }

            valueMap.put(AttendData.ORG_ID, data.getOrgId());
            valueMap.put(AttendData.DEPT_ID, data.getDeptId());

            calMap.put(calendar, valueMap);
            if (!attendDataMap.containsKey(data.getStaffId())) {
                attendDataMap.put(data.getStaffId(), calMap);
            }

            if (MapUtils.isNotEmpty(data.getMapBillTypeData())) {
                Map<String, Object> map = new HashMap<>();
                map.putAll(data.getMapBillTypeData());
                typeDataMap.put(calendar, map);
            }
            if (!extDataMap.containsKey(data.getStaffId())) {
                extDataMap.put(data.getStaffId(), typeDataMap);
            }
        }
        resultMap.put("data", attendDataMap);
        resultMap.put("extData", extDataMap);
        if(CollectionUtils.isNotEmpty(dataList) && dataList.size() == 1){
            log.debug("###attend-queryAttendData result:{}",resultMap);
        }
        return resultMap;
    }
    @Transactional
    public Map<String, Map<String, Map<String, Map<String, Object>>>> queryAttendDataNew(String[] staff_ids, Date beginDate, Date endDate, AttendSchemeVO attendSchemeVO,boolean isTask, List<AttendStaff> attendStaffList, Map<String, Object> allDatas) {
        List<AttendData> dataList = null;
        try {
            dataList = attendDataDateHelperService.getAttendData(beginDate, endDate, staff_ids, attendSchemeVO, isTask,attendStaffList,allDatas);
        } catch (Exception e) {
            log.error("-------------------生成考勤数据时失败---------");
            log.error(e.getMessage(), e);
            throw new AdderBusinessException("生成考勤数据时失败{0}", "attend.report.i18n45", e.getMessage());
        }

        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        Map<String, Map<String, Map<String, Map<String, Object>>>> resultMap = new HashMap<>();
        Map<String, Map<String, Map<String, Object>>> attendDataMap = new HashMap<>();//考勤数据
        Map<String, Map<String, Map<String, Object>>> extDataMap = new HashMap<>();//业务单据类型数据
        Map<String, Map<String, Object>> calMap = new HashMap<>();
        Map<String, Map<String, Object>> typeDataMap = new HashMap<>();
        String staff_id = "";
        // 查出班次ID map赋值班次名称用
        for (AttendData data : dataList) {
            if (null != staff_id && !staff_id.equals(data.getStaffId())) {
                calMap = new HashMap<>();
                typeDataMap = new HashMap<>();
            }
            staff_id = data.getStaffId();
            Map<String, Object> valueMap = new HashMap<>();
            String calendar = DateUtil.DateToString(data.getCalendar(), DateStyle.YYYY_MM_DD);
            valueMap.put(AttendData.CALENDAR, calendar);//日期
            valueMap.put(AttendData.ACTUALWORKHOURS, data.getActualworkhours());
            valueMap.put(AttendData.ACTUALWORKDAYS, data.getActualworkdays());
            valueMap.put(AttendData.WORKHOURS, data.getWorkhours());
            valueMap.put(AttendData.WORKDAYS, data.getWorkdays());
            valueMap.put(AttendData.UNNORMALLEN, data.getUnnormallen());
            valueMap.put(AttendData.LATELONG, data.getLatelong());
            valueMap.put(AttendData.EARLYLONG, data.getEarlylong());
            valueMap.put(AttendData.ABSENTHOUR, data.getAbsenthour());
            valueMap.put(AttendData.LATECOUNT, data.getLatecount());
            valueMap.put(AttendData.EARLYCOUNT, data.getEarlycount());
            valueMap.put(AttendData.RESIGNCNT, data.getResigncnt());
            valueMap.put(AttendData.ISABSENT, data.isIsabsent() ? 1 : 0);
            valueMap.put(AttendData.ABSENTCOUNT, data.getAbsentcount());
            valueMap.put(AttendData.ISNORMAL, data.isIsnormal());
            valueMap.put(AttendData.ISHOLIDAY, data.isIsholiday());
            valueMap.put(AttendData.BILLSTATEPASS, data.getBillStatePass());

            valueMap.put(AttendData.SIGNBEGINTIME, data.getSignbegintime());
            valueMap.put(AttendData.SIGNENDTIME, data.getSignendtime());
            valueMap.put(AttendData.SHIFT_ID, data.getShiftId());

            valueMap.put(AttendData.FIRSTBEGINSIGN, data.getFirstBeginsign());
            valueMap.put(AttendData.FIRSTBEGINSIGNSTATUS, data.getFirstBeginsignStatus());
            valueMap.put(AttendData.FIRSTENDSIGN, data.getFirstEndsign());
            valueMap.put(AttendData.FIRSTENDSIGNSTATUS, data.getFirstEndsignStatus());

            valueMap.put(AttendData.SECONDBEGINSIGN, data.getSecondBeginsign());
            valueMap.put(AttendData.SECONDBEGINSIGNSTATUS, data.getSecondBeginsignStatus());
            valueMap.put(AttendData.SECONDENDSIGN, data.getSecondEndsign());
            valueMap.put(AttendData.SECONDENDSIGNSTATUS, data.getSecondEndsignStatus());


            valueMap.put(AttendData.ISLEAVE, data.isIsleave());
            valueMap.put(AttendData.LEAVECNT, data.getLeavecnt());
            valueMap.put(AttendData.TRIPCNT, data.getTripcnt());
            valueMap.put(AttendData.RULEID, data.getRuleid());
            valueMap.put(AttendData.NOBRUSHCOUNT, data.getNobrushcount());
            valueMap.put(AttendData.UNNORMALCOUNT, data.getUnnormalcount());
            valueMap.put(AttendData.ISFULLDUTY, data.getIsfullduty());
            valueMap.put(AttendData.OUTSIDECOUNT, data.getOutsidecount());
            valueMap.put(AttendData.ISOUTSIDE, data.isIsoutside());
            valueMap.put("countrycode", data.getCountrycode());//国家编码
            valueMap.put(AttendData.DATETYPE, data.getDateType());//日期类型

            if (!StringUtils.isEmpty(data.getShiftId())) {
                Map<String,Shift> shiftMap =(Map<String,Shift>)allDatas.get(DataSetConstant.TSSHIFT);
                Shift shift = null;
                if(shiftMap.containsKey(data.getShiftId())) shift = shiftMap.get(data.getShiftId());
                if (shift == null) {
                    valueMap.put(AttendData.SHIFT_NAME, MultilingualTranslateHelper.getRest());
                } else {
                    valueMap.put(AttendData.SHIFT_NAME,  MultiLangHelper.getLangName(shift,"shiftname"));
                    valueMap.put(AttendData.SHIFTBEGINTIME, shift.getBegintime());
                    valueMap.put(AttendData.SHIFTENDTIME, shift.getEndtime());
                }
            }

            valueMap.put(AttendData.ORG_ID, data.getOrgId());
            valueMap.put(AttendData.DEPT_ID, data.getDeptId());

            calMap.put(calendar, valueMap);
            if (!attendDataMap.containsKey(data.getStaffId())) {
                attendDataMap.put(data.getStaffId(), calMap);
            }

            if (MapUtils.isNotEmpty(data.getMapBillTypeData())) {
                Map<String, Object> map = new HashMap<>();
                map.putAll(data.getMapBillTypeData());
                typeDataMap.put(calendar, map);
            }
            if (!extDataMap.containsKey(data.getStaffId())) {
                extDataMap.put(data.getStaffId(), typeDataMap);
            }
        }
        resultMap.put("data", attendDataMap);
        resultMap.put("extData", extDataMap);
        return resultMap;
    }

    @Transactional
    public Map<String, Map<String, Map<String, Map<String, Object>>>> queryAttendData(String[] staff_ids, Date beginDate, Date endDate, AttendSchemeVO attendSchemeVO, Map<String, Shift> shiftMap, boolean isTask,List<AttendStaff> attendStaffList){
        List<AttendData> dataList = null;
        try {
            dataList = attendDataService.getAttendData(beginDate, endDate, staff_ids, attendSchemeVO, shiftMap, isTask,attendStaffList);
        } catch (Exception e) {
            log.error("-------------------生成考勤数据时失败---------");
            log.error(e.getMessage(), e);
            throw new AdderBusinessException("生成考勤数据时失败{0}", "attend.report.i18n45", e.getMessage());
        }

        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        Map<String, Map<String, Map<String, Map<String, Object>>>> resultMap = new HashMap<>();
        Map<String, Map<String, Map<String, Object>>> attendDataMap = new HashMap<>();//考勤数据
        Map<String, Map<String, Map<String, Object>>> extDataMap = new HashMap<>();//业务单据类型数据
        Map<String, Map<String, Object>> calMap = new HashMap<>();
        Map<String, Map<String, Object>> typeDataMap = new HashMap<>();
        String staff_id = "";
        // 查出班次ID map赋值班次名称用
        for (AttendData data : dataList) {
            if (null != staff_id && !staff_id.equals(data.getStaffId())) {
                calMap = new HashMap<>();
                typeDataMap = new HashMap<>();
            }
            staff_id = data.getStaffId();
            Map<String, Object> valueMap = new HashMap<>();
            String calendar = DateUtil.DateToString(data.getCalendar(), DateStyle.YYYY_MM_DD);
            valueMap.put(AttendData.CALENDAR, calendar);//日期
            valueMap.put(AttendData.ACTUALWORKHOURS, data.getActualworkhours());
            valueMap.put(AttendData.ACTUALWORKDAYS, data.getActualworkdays());
            valueMap.put(AttendData.WORKHOURS, data.getWorkhours());
            valueMap.put(AttendData.WORKDAYS, data.getWorkdays());
            valueMap.put(AttendData.UNNORMALLEN, data.getUnnormallen());
            valueMap.put(AttendData.LATELONG, data.getLatelong());
            valueMap.put(AttendData.EARLYLONG, data.getEarlylong());
            valueMap.put(AttendData.ABSENTHOUR, data.getAbsenthour());
            valueMap.put(AttendData.LATECOUNT, data.getLatecount());
            valueMap.put(AttendData.EARLYCOUNT, data.getEarlycount());
            valueMap.put(AttendData.RESIGNCNT, data.getResigncnt());
            valueMap.put(AttendData.ISABSENT, data.isIsabsent() ? 1 : 0);
            valueMap.put(AttendData.ABSENTCOUNT, data.getAbsentcount());
            valueMap.put(AttendData.ISNORMAL, data.isIsnormal());
            valueMap.put(AttendData.ISHOLIDAY, data.isIsholiday());
            valueMap.put(AttendData.BILLSTATEPASS, data.getBillStatePass());

            valueMap.put(AttendData.SIGNBEGINTIME, data.getSignbegintime());
            valueMap.put(AttendData.SIGNENDTIME, data.getSignendtime());
            valueMap.put(AttendData.SHIFT_ID, data.getShiftId());

            valueMap.put(AttendData.FIRSTBEGINSIGN, data.getFirstBeginsign());
            valueMap.put(AttendData.FIRSTBEGINSIGNSTATUS, data.getFirstBeginsignStatus());
            valueMap.put(AttendData.FIRSTENDSIGN, data.getFirstEndsign());
            valueMap.put(AttendData.FIRSTENDSIGNSTATUS, data.getFirstEndsignStatus());

            valueMap.put(AttendData.SECONDBEGINSIGN, data.getSecondBeginsign());
            valueMap.put(AttendData.SECONDBEGINSIGNSTATUS, data.getSecondBeginsignStatus());
            valueMap.put(AttendData.SECONDENDSIGN, data.getSecondEndsign());
            valueMap.put(AttendData.SECONDENDSIGNSTATUS, data.getSecondEndsignStatus());


            valueMap.put(AttendData.ISLEAVE, data.isIsleave());
            valueMap.put(AttendData.LEAVECNT, data.getLeavecnt());
            valueMap.put(AttendData.TRIPCNT, data.getTripcnt());
            valueMap.put(AttendData.RULEID, data.getRuleid());
            valueMap.put(AttendData.NOBRUSHCOUNT, data.getNobrushcount());
            valueMap.put(AttendData.UNNORMALCOUNT, data.getUnnormalcount());
            valueMap.put(AttendData.ISFULLDUTY, data.getIsfullduty());
            valueMap.put(AttendData.OUTSIDECOUNT, data.getOutsidecount());
            valueMap.put(AttendData.ISOUTSIDE, data.isIsoutside());
            valueMap.put("countrycode", data.getCountrycode());//国家编码
            valueMap.put(AttendData.DATETYPE, data.getDateType());//日期类型

            if (!StringUtils.isEmpty(data.getShiftId())) {
                Shift shift = shiftMap.get(data.getShiftId());
                if (shift == null) {
                    valueMap.put(AttendData.SHIFT_NAME, MultilingualTranslateHelper.getRest());
                } else {
                    valueMap.put(AttendData.SHIFT_NAME, MultiLangHelper.getLangName(shift,"shiftname"));
                    valueMap.put(AttendData.SHIFTBEGINTIME, shift.getBegintime());
                    valueMap.put(AttendData.SHIFTENDTIME, shift.getEndtime());
                }
            }

            valueMap.put(AttendData.ORG_ID, data.getOrgId());
            valueMap.put(AttendData.DEPT_ID, data.getDeptId());

            calMap.put(calendar, valueMap);
            if (!attendDataMap.containsKey(data.getStaffId())) {
                attendDataMap.put(data.getStaffId(), calMap);
            }

            if (MapUtils.isNotEmpty(data.getMapBillTypeData())) {
                Map<String, Object> map = new HashMap<>();
                map.putAll(data.getMapBillTypeData());
                typeDataMap.put(calendar, map);
            }
            if (!extDataMap.containsKey(data.getStaffId())) {
                extDataMap.put(data.getStaffId(), typeDataMap);
            }
        }
        resultMap.put("data", attendDataMap);
        resultMap.put("extData", extDataMap);
        if(CollectionUtils.isNotEmpty(dataList) && dataList.size() == 1){
            log.debug("###attend-queryAttendData result:{}",resultMap);
        }
        return resultMap;
    }

    @Override
    public Map<String, Map<String, Map<String, Object>>> queryBills(String[] staff_ids, Date beginDate, Date endDate, AttendSchemeVO attendSchemeVO, boolean isTask) {
        //加班记录-看规则是啥 只能是按自动生成以或者加班单 这两种方式的一种
        OvertimeRule overtimeRule = iGenericService.load(OvertimeRule.class, attendSchemeVO.getOvertimeRuleId());
        Map<String, List<OvertimeSplitBillVO>> otMap = null;
        try {
            otMap = attendDataService.queryOvertimeSplitBills(null, beginDate, endDate, isTask ? null : staff_ids, HRCloudConst.BILL_STATUS_APPROVED_PASS);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }

        // 每人的请假单据
        Map<String, List<LeaveApplyDetail>> leaveMap = attendDataService.queryLeaveApply(beginDate, endDate, isTask ? null : staff_ids);
        //出差单
        Map<String, List<BusinessTripApplyDetail>> tripMap = attendDataService.queryBusinessTripApply(beginDate, endDate, isTask ? null : staff_ids);
        //打卡记录
        Map<String, List<AttendRecord>> recordMap = attendDataService.queryAttendRecord(beginDate, endDate, isTask ? null : staff_ids);
        // 结果集Map
        Map<String, Map<String, Map<String, Object>>> resultMap = new HashMap<>();
        // 开始结束日期数组
        Date[] dates = TimePubUtils.createDateArray(beginDate, endDate);

        //日报生成范围可能存在跨年的情况
        Condition hCond = new Condition();
        SimpleDateFormat yearSdf = new SimpleDateFormat("yyyy");
        ChainLogicExpression cle = new ChainLogicExpression(true,
                new ValueExpression("year", yearSdf.format(beginDate), "="),
                new ValueExpression("year", yearSdf.format(endDate), "="));
        hCond.addExpressions(cle);
        Map<String, List<Holiday>> holidayMap = holidayService.queryHolidayMapByConditon(hCond);
        List<LeaveTypeNew> leaveTypeNews = leaveTypeNewService.getAllLeaveTyeNews(attendSchemeVO.getLeaveRuleId());
        Map<String, LeaveTypeNew> leaveTypeNewMap = TimePubUtils.group2VOById(leaveTypeNews);

        Map<String, Map<Date, String>> calendarMap = null;
        boolean isSernior = itimeCommonService.isSeniorVersion();
        Map<String, TsAttendRuleVO> staffRuleMap = ruleService.queryByStaffIdAndOrgId(Arrays.asList(staff_ids));

        if (null == staffRuleMap) {
            return null;
        }
        calendarMap = createCalendarMap4Diwork(staff_ids, beginDate, endDate, staffRuleMap);
        if (null == calendarMap || calendarMap.size() == 0) {
            return null;
        }

        //不同考勤规则只能获取所有按班次
        List<Shift> shiftList = shiftservice.queryListByConditon(null);
        Map<String, Shift> shiftMap = TimePubUtils.group2VOById(shiftList);

        List<WorkingCalendar> workCalendarList = holidayService.queryWorkingCalendar(null);
        Map<String, WorkingCalendar> workCalendarIdMap = TimePubUtils.group2VOById(workCalendarList);
        if (null == workCalendarIdMap) {
            return null;
        }

        // 按人循环构造map
        for (String staff_id : staff_ids) {
            Map<Date, String> dateShiftMap = calendarMap.get(staff_id);
            // 如果没有排班，则不计算其考勤日报
            if (null == dateShiftMap) {
                continue;
            }
            // 构造key为data， value为某个休假类别对应的时长的Map
            Map<String, Map<String, Object>> calMap = new HashMap<>();
            List<LeaveApplyDetail> staffLeaves = null;
            if (null != leaveMap) {
                staffLeaves = leaveMap.get(staff_id);
            }

            List<OvertimeSplitBillVO> splitVos = null;
            if (null != otMap) {
                splitVos = otMap.get(staff_id);
            }
            List<AttendRecord> records = null;
            if (null != recordMap) {
                records = recordMap.get(staff_id);
            }

            TsAttendRuleVO rulevo = staffRuleMap.get(staff_id);
            if (rulevo == null)
                continue;
            if (null == rulevo.getWorkCalendarId())
                continue;
            WorkingCalendar workCalendar = workCalendarIdMap.get(rulevo.getWorkCalendarId());
            // 每人的每天
            for (int i = 0; i < dates.length; i++) {
                Map<String, Object> valueMap = new HashMap<>();//key是typeid value是时长
                Date date = dates[i];
                // 每天的上班时间
                String shift_id = null;
                //非排班制直接考勤规则取班次id
                if (!"1".equals(rulevo.getShiftModeFix())) {
                    shift_id = rulevo.getShiftId();
                } else {
                    for (Map.Entry<Date, String> map : dateShiftMap.entrySet()) {
                        if (date.equals(map.getKey())) {
                            shift_id = map.getValue();// 当日排班
                            continue;
                        }
                    }
                }

                if (null == shift_id || shift_id.endsWith(IAttendConst.SHIFT_GX)
                        || (!"1".equals(rulevo.getShiftModeFix()) && !attendCommonService.checkIsWorkdate(date, workCalendar))) {//没排班或者排的班次是公休
                    //处理加班单据--周末或者节假日的也需要处理
                    if (null != overtimeRule) {
                        processOtBills(splitVos, date, valueMap, overtimeRule);
                    }
                    //处理公休的请假时长
                    //处理公休的请假时长
                    if (null != shift_id && shift_id.endsWith(IAttendConst.SHIFT_GX)) {
                        Date[] dateScope = TimePubUtils.getDateStartEnd(date);
                        ITimeScope kqScope = new DefaultTimeScope(dateScope[0], dateScope[1]);// 公休班的开始结束时间-当天零点-23:59:59
                        // 与当天有交集的请假单据
                        ITimeScope[] scopeLeaves = null;
                        if (!CollectionUtils.isEmpty(staffLeaves)) {
                            scopeLeaves = DataFilterUtils.filterRegVOs(kqScope, staffLeaves);
                        }
                        processLeaveBills4GX(scopeLeaves, date, valueMap, leaveTypeNewMap, holidayMap.get(rulevo.getWorkCalendarId()), dateShiftMap);

                    }
                    calMap.put(DateUtil.DateToString(date, DateStyle.YYYY_MM_DD), valueMap);
                    if (!resultMap.containsKey(staff_id)) {
                        resultMap.put(staff_id, calMap);
                    }
                    continue;
                }
                Shift shiftvo = shiftMap.get(shift_id);

                if (shiftvo == null) {
                    log.debug(String.format("*********attend generateSenior shiftvo is null,人员(%s)在%s没有排班",
                            staff_id, date));
                    continue;
                }

                AttendRecord[] recordDate = null;//与当天有交集的打卡数据--计算弹性班次用到
                if (!CollectionUtils.isEmpty(records)) {// 某人当天的签到记录
                    recordDate = getDateRecordList(records, date).toArray(new AttendRecord[0]);
                }

                ITimeScope kqScope = ElasticShiftUtils.getKqscope(shiftvo, date);// 班次的开始结束时间
                // 与当天有交集的请假单据
                ITimeScope[] scopeLeaves = null;
                if (!CollectionUtils.isEmpty(staffLeaves)) {
                    scopeLeaves = DataFilterUtils.filterRegVOs(kqScope, staffLeaves);
                }
                //单据合并放在一个数组里便于计算迟到早退
                ITimeScope[] mergeLASScopes = TimeScopeUtils.mergeTimeScopes(scopeLeaves, null);
                //工作时间段，弹性和非弹性的工作时间段算法不同
                //弹性的需要 把所有的单据和他的打卡时间放在一起固化出一个最合适的上下班时间点用于计算
                ITimeScope[] workTimeScopes = null;
                if (1 == shiftvo.getShiftType()) {//非弹性
                    workTimeScopes = TimePubUtils.getWorkTimeScopes(date, shiftvo);
                } else {//弹性
                    if (null == shiftvo.getElasticRule() || 1 == shiftvo.getElasticRule()) {//按日弹
                        workTimeScopes = (ITimeScope[]) ElasticShiftaAttendUtils.getBegEndTime4Tanxing(kqScope, recordDate, mergeLASScopes, shiftvo, date);
                    } else {//按月弹
                        workTimeScopes = (ITimeScope[]) ElasticShiftaAttendUtils.getBegEndTime4MonthTanxing(shiftvo, date);
                    }
                }
                /**处理请假**/
                processLeaveBills(scopeLeaves, shiftvo, date, valueMap, leaveTypeNewMap, workTimeScopes);
                /**处理加班**/
                if (null != overtimeRule) {
                    processOtBills(splitVos, date, valueMap, overtimeRule);
                }
                calMap.put(DateUtil.DateToString(date, DateStyle.YYYY_MM_DD), valueMap);
                if (!resultMap.containsKey(staff_id)) {
                    resultMap.put(staff_id, calMap);
                }
            }
        }
        return resultMap;
    }

    /**
     * key是人 map 是 《休假类别，月度汇总值》
     *
     * @param staff_ids
     * @param year
     * @param month
     * @return
     */
    @Override
    public Map<String, Map<String, Object>> queryMonthBills(String[] staff_ids, String year, String month, AttendSchemeVO attendSchemeVO, boolean isTask) {
        // 查日报上每人每月的
        // 查每月的开始结束日期
        Condition periodCond = new Condition();
        periodCond.addExpression("year", year, "=");
        periodCond.addExpression("month", month, "=");
        periodCond.addExpression("main_id", attendSchemeVO.getPeriodSchemeId());
        List<AttendPeriod> periods = periodService.queryListByCondition(periodCond);
        if (CollectionUtils.isEmpty(periods)) {
            throw new AdderBusinessException("考勤期间不存在", "attend.report.i18n26");
        }
        Date begindate = periods.get(0).getBegindate();
        Date enddate = periods.get(0).getEnddate();
        Condition monthCond = new Condition();
        monthCond.addExpression("calendar", begindate, ">=");
        monthCond.addExpression("calendar", enddate, "<=");
        monthCond.addExpression("staff_id", staff_ids, "in");
        List<Map> monthBills = attendDataService.queryTimeitemBills4Month(monthCond);
        if (CollectionUtils.isEmpty(monthBills)) {
            return null;
        }
        log.debug("###attend-queryMonthBills,cond:{}", JSONObject.toJSONString(monthCond));
        // 结果集Map
        Map<String, Map<String, Object>> resultMap = new HashMap<>();
        Map<String, Object> tiemitemMap = null;
        //添加考勤项目字段
        Map<String,String> itemMap = queryKQItem();
        for (int i = 0; i < monthBills.size(); i++) {
        	//设置
            Map map = monthBills.get(i);
            String mapKey = String.format ("%s_%s",getUpperCaseValue(map,"staff_id"),getUpperCaseValue(map,"org_id"));
            if (!resultMap.containsKey(mapKey)) {
                tiemitemMap = new HashMap<>();
                resultMap.put(mapKey, tiemitemMap);
            } else {
                tiemitemMap = resultMap.get(mapKey);
            }
            String pk_timeitem = (String) getUpperCaseValue(map,"pk_timeitem");
            BigDecimal hournum_sum = (BigDecimal)getUpperCaseValue(map,"hournum_sum");
            tiemitemMap.put(pk_timeitem, hournum_sum);
            
            //chenzf 查询子表数据
            log.debug("#####attend 查询子表1：TsAttendRptCoreBusinessServiceImpl queryMonthBills queryGlbdef3 begin");
            String month1 = month;
        	if(month != null && month.length() == 1) {
        		month1 = "0" + month;
        	}
            Map<String, Object> glbdef3Map = this.queryGlbdef3(getUpperCaseValue(map,"staff_id").toString(), year, month1);
            if(glbdef3Map != null) {
            	log.debug("#####attend 查询子表1：TsAttendRptCoreBusinessServiceImpl queryMonthBills queryGlbdef3 glbdef3:"+ JSON.toJSONString(glbdef3Map));
            	tiemitemMap.put(itemMap.get("平时中午加班次数"), glbdef3Map.get("GLBDEF3"));//平时中午加班次数
            	tiemitemMap.put(itemMap.get("平时晚上加班次数"), glbdef3Map.get("GLBDEF4"));//平时晚上加班次数
            	tiemitemMap.put(itemMap.get("周末加班次数"), glbdef3Map.get("GLBDEF5"));//周末加班次数
            	tiemitemMap.put(itemMap.get("节假日加班次数"), glbdef3Map.get("GLBDEF6"));//节假日加班次数
            	tiemitemMap.put(itemMap.get("平时加班时长"), glbdef3Map.get("GLBDEF7"));//平时加班时长
            	tiemitemMap.put(itemMap.get("周末加班时长"), glbdef3Map.get("GLBDEF8"));//周末加班时长
            	tiemitemMap.put(itemMap.get("节假日加班时长"), glbdef3Map.get("GLBDEF9"));//节假日加班时长
//            	BigDecimal glbdef10 = new BigDecimal(glbdef3Map.get("glbdef10").toString()).add(new BigDecimal(glbdef3Map.get("glbdef11").toString())).add(new BigDecimal(glbdef3Map.get("glbdef12").toString()));
//            	tiemitemMap.put("", glbdef10);//调休时长
            }
        
        }
        log.debug("###attend-queryMonthBills,resultMap:{}", resultMap);
        return resultMap;
    }
    
    /**
     * 查询人员子集
     * @param pk_psndoc
     * @param year
     * @param month
     * @return
     */
    public Map<String, Object> queryGlbdef3(String pk_psndoc,String year,String month){
    	List<Map> list = iAttendRptCalDao.queryGlbdef3(pk_psndoc, year, month);
    	if(list != null && list.size() > 0) {
    		return list.get(0);
    	}
    	return null;
    }
    
    public Map<String,String> queryKQItem(){
    	Map<String,String> map = new HashMap();
    	List<Map> list = iAttendRptCalDao.queryKQItem();
    	if(list != null && list.size() > 0) {
    		for(Map lmap : list) {
    			map.put(lmap.get("name").toString(), lmap.get("id").toString());
    		}
    	}
    	return map;
    }

    private Object getUpperCaseValue(Map map,String key)
    {
        Object objectvalue=map.get(key);
        if(objectvalue==null){
            objectvalue=map.get(key.toUpperCase());
        }
        return objectvalue;
    }

    /**
     * 如果日期范围有考勤日报数据就直接返回，如果没有也返回rptvo 里面只有基础信息staffid 日期这些
     *
     * @param staff_ids
     * @param year
     * @param month
     * @param attendSchemeVO
     * @return
     */
    @Override
    public List<AttendMonthRptVO> queryRpt4CalMonth(String[] staff_ids, String year, String month, AttendSchemeVO attendSchemeVO, boolean isTask, AttendPeriod period) {
        //当前月所属期间的开始结束日期
        if (period == null) {
            Condition periodCond = new Condition();
            periodCond.addExpression("year", year, "=");
            periodCond.addExpression("month", month, "=");
            periodCond.addExpression("main_id", attendSchemeVO.getPeriodSchemeId(), "=");
            List<AttendPeriod> periods = periodService.queryListByCondition(periodCond);
            if (CollectionUtils.isEmpty(periods)) {
                throw new AdderBusinessException("考勤期间不存在", "attend.report.i18n26");
            }
            period = periods.get(0);
        }
        Date beginDate = period.getBegindate();
        Date endDate = period.getEnddate();
        //boolean isSenior = itimeCommonService.isSeniorVersion();
        List<AttendStaff> attendStaffsList;
        Condition attendStaffCond = new Condition();
        LogicExpression staffLe = new LogicExpression(
                new LogicExpression(new ValueExpression("ts_attend_staff.begindate", endDate, "<="),
                        new ValueExpression("ts_attend_staff.enddate", beginDate, ">="), false),
                new LogicExpression(new ValueExpression("ts_attend_staff.begindate", endDate, "<="),
                        new ValueExpression("ts_attend_staff.enddate", null, Operator.ISNULL.getCode()), false),
                true);
        attendStaffCond.addExpressions(staffLe);
        if (!isTask) {
            attendStaffCond.addExpression("ts_attend_staff.staff_id", staff_ids, "in");
        }
        //临时增加条件 blast=1，处理跨组织时再放开
        attendStaffCond.addExpression("ts_attend_staff.islast", "1");

        attendStaffCond.addExpression("ts_attend_staff.attend_type", TimeConst.ATTEND_TYPE_NO, "<>");//不考勤的要过滤掉
        attendStaffsList = attendStaffService.queryByConditon(attendStaffCond, new Sorter("begindate"));

        //查询已经有的月报
        Map<String, AttendMonthRptVO> existMonthRpts = rptService.queryLastMonthByCondition(isTask ? null : staff_ids, year, month);
        if (null == existMonthRpts) {
            return null;
        }
        List<AttendMonthRptVO> resultVo = new ArrayList<>();
        for (AttendStaff as : attendStaffsList) {
            String staff_id = as.getStaffId();
            AttendMonthRptVO monthVo = existMonthRpts.get(staff_id);
            ////对于先导入月报，再导出的客户，可能会导致查询ts_monthstat的时候dept_id为空，从而导致直接返回一个空的月报模板，故将逻辑改为如下：
            if (monthVo == null) {
                 monthVo = new AttendMonthRptVO();
            }
            monthVo.setStaffId(staff_id);
            monthVo.setOrgId(as.getOrgId());
            monthVo.setDeptId(as.getDeptId());
            monthVo.setJobId(as.getStaffjobId());
            monthVo.setStaffName(as.getStaffName());
            monthVo.setOrgName(as.getOrgName());

            //chenzf 计算
        	log.debug("#####attend 查询子表1：TsAttendRptCoreBusinessServiceImpl queryRpt4CalMonth queryGlbdef3 begin");
        	String month1 = month;
        	if(month != null && month.length() == 1) {
        		month1 = "0" + month;
        	}
        	Map<String, Object> glbdef3Map = this.queryGlbdef3(as.getStaffId(), year, month1);
            if(glbdef3Map != null) {
            	log.debug("#####attend 查询子表1：TsAttendRptCoreBusinessServiceImpl queryRpt4CalMonth queryGlbdef3 glbdef3:"+ JSON.toJSONString(glbdef3Map));
            	//平时中午加班次数
            	monthVo.setF_n_1(new BigDecimal(glbdef3Map.get("GLBDEF3") == null ? "0" : glbdef3Map.get("GLBDEF3").toString()));
            	//平时晚上加班次数
            	monthVo.setF_n_2(new BigDecimal(glbdef3Map.get("GLBDEF4") == null ? "0" : glbdef3Map.get("GLBDEF4").toString()));
            	//周末加班次数
            	monthVo.setF_n_3(new BigDecimal(glbdef3Map.get("GLBDEF5") == null ? "0" : glbdef3Map.get("GLBDEF5").toString()));
            	//节假日加班次数
            	monthVo.setF_n_4(new BigDecimal(glbdef3Map.get("GLBDEF6") == null ? "0" : glbdef3Map.get("GLBDEF6").toString()));
            	//平时加班时长
            	monthVo.setF_n_5(new BigDecimal(glbdef3Map.get("GLBDEF7") == null ? "0" : glbdef3Map.get("GLBDEF7").toString()));
            	//周末加班时长
            	monthVo.setF_n_6(new BigDecimal(glbdef3Map.get("GLBDEF8") == null ? "0" : glbdef3Map.get("GLBDEF8").toString()));
            	//节假日加班时长
            	monthVo.setF_n_7(new BigDecimal(glbdef3Map.get("GLBDEF9") == null ? "0" : glbdef3Map.get("GLBDEF9").toString()));
            }
            
            resultVo.add(monthVo);
            //log.error("++++++++++++++++++++++++++++++++++++++resultVo = " +JSONObject.toJSONString(resultVo));
            //log.error("++++++++++++++++++++++++++++++++++++++resultVo = " +JSONObject.toJSONString(monthVo));
            //对于先导入月报，再导出的客户，可能会导致查询ts_monthstat的时候dept_id为空，从而导致直接返回一个空的月报模板
//            if (null != monthVo) {//一个月的每人最多只有一条  TODO 后面要考虑跨组织调动的场景
//                resultVo.add(monthVo);
//            } else {// 没有new 一个只包含staff_id这些基础字段的
//                AttendMonthRptVO newVo = new AttendMonthRptVO();
//                newVo.setStaffId(staff_id);
//                newVo.setOrgId(as.getOrgId());
//                newVo.setDeptId(as.getDeptId());
//                newVo.setJobId(as.getStaffjobId());
//                newVo.setStaffName(as.getStaffName());
//                newVo.setOrgName(as.getOrgName());
//                resultVo.add(newVo);
//            }
        }
        return resultVo;
    }

    @Override
    public List<AttendMonthRptVO> queryRpt4CalMonth(AttendRptParams params) {
        //当前月所属期间的开始结束日期
        if (params.getAttendPeriod() == null) {
            Condition periodCond = new Condition();
            periodCond.addExpression("year", params.getYear(), Operator.EQUAL);
            periodCond.addExpression("month", params.getMonth(), Operator.EQUAL);
            periodCond.addExpression("main_id", params.getAttendSchemeVO().getPeriodSchemeId(), Operator.EQUAL);
            List<AttendPeriod> periods = periodService.queryListByCondition(periodCond);
            if (CollectionUtils.isEmpty(periods)) {
                throw new AdderBusinessException("考勤期间不存在", "attend.report.i18n26");
            }
            params.setAttendPeriod(periods.get(0));
        }
        List<AttendStaff> attendStaffsList = params.getAttendStaffList();
        if(CollectionUtils.isEmpty(attendStaffsList)) {
            attendStaffsList = queryAttendStaff(params);
        }
        //查询已经有的月报
        Map<String, AttendMonthRptVO> existMonthRpts = rptService.queryMonthRptGroupByOrg(params.getListStaffIds().toArray(new String[0]), params.getYear(), params.getMonth(),params.getAttendSchemeVO().getOrgs());
        /*if (MapUtils.isEmpty(existMonthRpts)) {
            return null;
        }*/
        Date maxEndDate = DateUtil.StringToDate("9999-01-01",DateStyle.YYYY_MM_DD);
        List<String> listKeys = new ArrayList<>();
        List<AttendMonthRptVO> resultVo = new ArrayList<>();
        for (AttendStaff as : attendStaffsList) {
            if (TimeConst.ATTEND_TYPE_NO.equals(as.getAttendType())) {
                continue;
            }
            if(!validateDate(params.getAttendPeriod().getBegindate(),params.getAttendPeriod().getEnddate(),as.getBegindate(),as.getEnddate() == null ? maxEndDate : as.getEnddate())) {
                continue;
            }
            String key = String.format("%s_%s",as.getStaffId(),as.getOrgId());
            if(listKeys.contains(key)) {
                continue;
            }
            AttendMonthRptVO monthRptVO = existMonthRpts.get(key);
            if(monthRptVO == null){
                monthRptVO = new AttendMonthRptVO();
            }
            monthRptVO.setStaffId(as.getStaffId());
            monthRptVO.setStaffCode(as.getStaffCode());
            monthRptVO.setOrgId(as.getOrgId());
            monthRptVO.setDeptId(as.getDeptId());
            monthRptVO.setDeptName(as.getDeptName());
            monthRptVO.setJobId(as.getStaffjobId());
            monthRptVO.setStaffName(as.getStaffName());
            monthRptVO.setOrgName(as.getOrgName());
            
            //chenzf 计算
            log.debug("#####attend 查询子表2：TsAttendRptCoreBusinessServiceImpl queryRpt4CalMonth queryGlbdef3 begin");
            String month1 = params.getMonth();
        	if(month1 != null && month1.length() == 1) {
        		month1 = "0" + month1;
        	}
            Map<String, Object> glbdef3Map = this.queryGlbdef3(as.getStaffId(), params.getYear(), month1);
            if(glbdef3Map != null) {
            	log.debug("#####attend 查询子表2：TsAttendRptCoreBusinessServiceImpl queryRpt4CalMonth queryGlbdef3 glbdef3:"+ JSON.toJSONString(glbdef3Map));
            	//平时中午加班次数
            	monthRptVO.setF_n_1(new BigDecimal(glbdef3Map.get("GLBDEF3") == null ? "0" : glbdef3Map.get("GLBDEF3").toString()));
            	//平时晚上加班次数
            	monthRptVO.setF_n_2(new BigDecimal(glbdef3Map.get("GLBDEF4") == null ? "0" : glbdef3Map.get("GLBDEF4").toString()));
            	//周末加班次数
            	monthRptVO.setF_n_3(new BigDecimal(glbdef3Map.get("GLBDEF5") == null ? "0" : glbdef3Map.get("GLBDEF5").toString()));
            	//节假日加班次数
            	monthRptVO.setF_n_4(new BigDecimal(glbdef3Map.get("GLBDEF6") == null ? "0" : glbdef3Map.get("GLBDEF6").toString()));
            	//平时加班时长
            	monthRptVO.setF_n_5(new BigDecimal(glbdef3Map.get("GLBDEF7") == null ? "0" : glbdef3Map.get("GLBDEF7").toString()));
            	//周末加班时长
            	monthRptVO.setF_n_6(new BigDecimal(glbdef3Map.get("GLBDEF8") == null ? "0" : glbdef3Map.get("GLBDEF8").toString()));
            	//节假日加班时长
            	monthRptVO.setF_n_7(new BigDecimal(glbdef3Map.get("GLBDEF9") == null ? "0" : glbdef3Map.get("GLBDEF9").toString()));
            }
            
            resultVo.add(monthRptVO);
            listKeys.add(key);
        }
        return resultVo;
    }

    private boolean validateDate(Date peroidBeginDate,Date peroidEndDate,Date beginDate,Date endDate){
        if(peroidBeginDate == null || peroidEndDate == null || beginDate == null || endDate == null) {
            return false;
        }
        if(peroidBeginDate.compareTo(endDate) > 0 || peroidEndDate.compareTo(beginDate) < 0) {
            return false;
        }
        return true;
    }

    /***
     * 查询假勤档案
     * @param params
     * @return
     */
    private List<AttendStaff> queryAttendStaff(AttendRptParams params){
        if(CollectionUtils.isEmpty(params.getListStaffIds())) {
            throw new AdderBusinessException("没有可计算人员!", "attend.report.i18n41");
        }
        Condition attendStaffCond = new Condition();
        /* LogicExpression staffLe = new LogicExpression(
                new LogicExpression(new ValueExpression("ts_attend_staff.begindate", params.getAttendPeriod().getBegindate(), "<="),
                        new ValueExpression("ts_attend_staff.enddate", params.getAttendPeriod().getEnddate(), ">="), false),
                new LogicExpression(new ValueExpression("ts_attend_staff.begindate", params.getAttendPeriod().getEnddate(), "<="),
                        new ValueExpression("ts_attend_staff.enddate", null, Operator.ISNULL.getCode()), false),
                true);
        attendStaffCond.addExpressions(staffLe);*/
        attendStaffCond.addExpression("ts_attend_staff.staff_id", params.getListStaffIds(), "in");
        attendStaffCond.addExpression("ts_attend_staff.attend_type", TimeConst.ATTEND_TYPE_NO, "<>");//不考勤的要过滤掉
        attendStaffCond.addExpression("dept_id",params.getAttendSchemeVO().getOrgs(),Operator.IN);
        return attendStaffService.queryByConditon(attendStaffCond, new Sorter("begindate"));
    }

    @Override
    public Map<String, Map<Date, String>> getCalendarMap4Diwork(List<String> staff_ids, Date beginDate, Date endDate) {
        //排班方式 0：固定排班 1：排班制，2：按天弹性班制，3：按考勤周期弹性排班制
        //1.先查询排班制的数据
        Map<String, Map<Date, String>> calendarData = calendarService.queryCalendarByDate(staff_ids.toArray(new String[0]), beginDate, endDate);
        //2.找出不包含的人员
        List<String> ruleStaffIds = new ArrayList<>();
        staff_ids.forEach(staffId -> {
            if (!calendarData.containsKey(staffId)) {
                ruleStaffIds.add(staffId);
            }
        });
        if (ruleStaffIds.size() == 0) {
            return calendarData;
        }
        //3.查询剩余人员的考勤规则
        Map<String, TsAttendRuleVO> staffRuleMap = ruleService.queryByStaffIdAndOrgId(ruleStaffIds);
        if (staffRuleMap == null || staffRuleMap.size() == 0) {
            return calendarData;
        }
        Date[] dates = TimePubUtils.createDateArray(beginDate, endDate);
        //4.人员按日期组装map
        for (String staffId : ruleStaffIds) {
            TsAttendRuleVO rulevo = staffRuleMap.get(staffId);
            if (null == rulevo) {
                continue;
            }
            String shift_id = rulevo.getShiftId();
            Map<Date, String> calShiftMap = new HashMap<>();
            for (int j = 0; j < dates.length; j++) {//每天的排班情况
                calShiftMap.put(dates[j], shift_id);
            }
            calendarData.put(staffId, calShiftMap);
        }
        return calendarData;
    }

    @Override
    public Map<String, Map<Date, String>> getCalendarMap4Diwork(List<String> staff_ids, Date beginDate, Date endDate, Map<String, TsAttendRuleVO> staffRuleMap) {
        //排班方式 0：固定排班 1：排班制，2：按天弹性班制，3：按考勤周期弹性排班制
        //1.先查询排班制的数据
        Map<String, Map<Date, String>> calendarData = calendarService.queryCalendarByDate(staff_ids.toArray(new String[0]), beginDate, endDate);
        if (staffRuleMap == null || staffRuleMap.size() == 0) {
            return calendarData;
        }
        if (calendarData == null || calendarData.size() == 0) {
            return calendarData;
        }
        Date[] dates = TimePubUtils.createDateArray(beginDate, endDate);
        //3.人员按日期组装map
        for (String staffId : staff_ids) {
            if (calendarData.containsKey(staffId)) {
                continue;
            }
            TsAttendRuleVO rulevo = staffRuleMap.get(staffId);
            if (null == rulevo) {
                continue;
            }
            String shift_id = rulevo.getShiftId();
            Map<Date, String> calShiftMap = new HashMap<>();
            for (int j = 0; j < dates.length; j++) {//每天的排班情况
                calShiftMap.put(dates[j], shift_id);
            }
            calendarData.put(staffId, calShiftMap);
        }
        return calendarData;
    }

    // 在某人所有刷卡记录里找出当天的记录
    public List<AttendRecord> getDateRecordList(List<AttendRecord> list, Date date) {
        List<AttendRecord> result = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            AttendRecord vo = list.get(i);
            if (vo.getSigndate().equals(date)) {
                result.add(vo);
            }
        }
        return result;
    }

    //处理请假数据
    public void processLeaveBills(ITimeScope[] scopeLeaves, Shift shiftvo, Date date, Map<String, Object> valueMap, Map<String, LeaveTypeNew> leaveTypeNewMap, ITimeScope[] workTimeScopes) {
        // 与当天有交集的请假单据
        // 每天的请假单
        if (!ArrayUtils.isEmpty(scopeLeaves)) {
            for (ITimeScope bill : scopeLeaves) {
                LeaveApplyDetail apply = (LeaveApplyDetail) bill;
                String type_id = apply.getLeavetypeid();
                LeaveTypeNew leaveTypeNew = leaveTypeNewMap.get(type_id);//假别
                if (null == leaveTypeNew) {
                    log.error(String.format("##### attend-processLeaveBills,假别(%s)不存在，跳过", type_id));
                    continue;
                }
                BigDecimal leavelength = null;
                try {
                    // TODO 这里dateType 传0无用 该方法暂无引用
                    leavelength = iLeaveApplyService.getLength4NormalShift
                            (apply.getLeavebegintime(), apply.getLeaveendtime(), shiftvo, date,
                                    leaveTypeNewMap.get(type_id), workTimeScopes,null,null,0);
                } catch (Exception ex) {
                    log.error(ex.getMessage(), ex);
                }
                if (valueMap.containsKey(type_id)) {//如果已经有该类别了
                    //原来的时长
                    BigDecimal oldLength = new BigDecimal(valueMap.get(type_id).toString());
                    valueMap.put(type_id, oldLength.add(leavelength));
                    processCommonLeaveType(valueMap, leaveTypeNew, oldLength.add(leavelength));
                } else {
                    valueMap.put(type_id, leavelength);
                    processCommonLeaveType(valueMap, leaveTypeNew, leavelength);
                }
            }
        }
    }

    //为了解决公式中的公共假别赋值，需要增加转换信息-liushm
    private void processCommonLeaveType(Map<String, Object> valueMap, LeaveTypeNew leaveTypeNew, BigDecimal leavelength) {
        if (StringUtils.isNotEmpty(leaveTypeNew.getRefId())) {
            valueMap.put(leaveTypeNew.getRefId(), leavelength);
        }
    }

    /**
     * 处理公休班次的请假数据
     */
    private void processLeaveBills4GX(ITimeScope[] scopeLeaves, Date date, Map<String, Object> valueMap, Map<String, LeaveTypeNew> leaveTypeNewMap,
                                      List<Holiday> holidayList, Map<Date, String> dateShiftMap) {
        // 与当天有交集的请假单据
        // 每天的请假单
        if (!ArrayUtils.isEmpty(scopeLeaves)) {
            for (ITimeScope bill : scopeLeaves) {
                LeaveApplyDetail apply = (LeaveApplyDetail) bill;
                String type_id = apply.getLeavetypeid();
                LeaveTypeNew leaveTypeNew = leaveTypeNewMap.get(type_id);//假别
                if (null == leaveTypeNew) {
                    log.error(String.format("##### attend-processLeaveBills4GX,假别(%s)不存在，跳过", type_id));
                    continue;
                }
                BigDecimal leavelength = null;
                try {
                    leavelength = iLeaveApplyService.getLeaveLength4GX(apply.getLeavebegintime(),
                            apply.getLeaveendtime(), date, leaveTypeNewMap.get(type_id), holidayList, dateShiftMap);
                } catch (Exception ex) {
                    log.error(ex.getMessage(), ex);
                }

                if (valueMap.containsKey(type_id)) {//如果已经有该类别了
                    //原来的时长
                    BigDecimal oldLength = new BigDecimal(valueMap.get(type_id).toString());
                    valueMap.put(type_id, oldLength.add(leavelength));
                    processCommonLeaveType(valueMap, leaveTypeNew, oldLength.add(leavelength));
                } else {
                    valueMap.put(type_id, leavelength);
                    processCommonLeaveType(valueMap, leaveTypeNew, leavelength);
                }
            }
        }
    }

    private Map<String, Map<Date, String>> createCalendarMap4Diwork(String[] staff_ids, Date beginDate, Date endDate, Map<String, TsAttendRuleVO> ruleMap) {
        //排班方式 0：固定排班 1：排班制，2：按天弹性班制，3：按考勤周期弹性排班制
        Map<String, Map<Date, String>> staffCalMap = new HashMap<>();
        Date[] dates = TimePubUtils.createDateArray(beginDate, endDate);
        for (int i = 0; i < staff_ids.length; i++) {
            TsAttendRuleVO rulevo = ruleMap.get(staff_ids[i]);
            if (null == rulevo) {
                continue;
            }
            if ("1".equals(rulevo.getShiftModeFix())) {
                Map<String, Map<Date, String>> map = calendarService.queryCalendarByDate(staff_ids, beginDate, endDate);
                if (map != null && map.size() > 0) {
                    staffCalMap.putAll(map);
                }
            } else {
                String shift_id = rulevo.getShiftId();
                Map<Date, String> calShiftMap = new HashMap<>();
                for (int j = 0; j < dates.length; j++) {//每天的排班情况
                    calShiftMap.put(dates[j], shift_id);
                }
                staffCalMap.put(staff_ids[i], calShiftMap);
            }
        }
        return staffCalMap;
    }

    /**
     * 高级版获取排班
     *
     * @param staff_ids
     * @param beginDate
     * @param endDate
     * @param ruleMap
     * @param calendarMap
     * @return
     */
    private Map<String, Map<Date, String>> createCalendarMap4Senior(String[] staff_ids, Date beginDate, Date endDate, Map<String, TsAttendRuleVO> ruleMap, Map<String, Map<Date, String>> calendarMap) {
        Map<String, Map<Date, String>> staffCalMap = new HashMap<>();
        Date[] dates = TimePubUtils.createDateArray(beginDate, endDate);
        for (int i = 0; i < staff_ids.length; i++) {
            //获取某人的考勤规则
            TsAttendRuleVO rulevo = ruleMap.get(staff_ids[i]);
            if (null == rulevo) {
                continue;
            }

            //排班制
            if ("1".equals(rulevo.getShiftModeFix())) {
                if (calendarMap == null) {
                    continue;
                }
                Map<Date, String> dateCalendarMap = calendarMap.get(staff_ids[i]);
                if (dateCalendarMap == null) {
                    continue;
                }

                Map<Date, String> calShiftMap = new HashMap<>();
                for (int j = 0; j < dates.length; j++) {//每天的排班情况
                    dateCalendarMap.get(dates[j]);
//                    calShiftMap.put(dates[j], shift_id);
                }
            }
            String shift_id = rulevo.getShiftId();
            Map<Date, String> calShiftMap = new HashMap<>();
            for (int j = 0; j < dates.length; j++) {//每天的排班情况
                calShiftMap.put(dates[j], shift_id);
            }
            staffCalMap.put(staff_ids[i], calShiftMap);
        }
        return staffCalMap;
    }

    //计算加班单据
    public void processOtBills(List<OvertimeSplitBillVO> splitVos, Date date, Map<String, Object> valueMap, OvertimeRule rule) {
        //先取加班规则，如果当天是按加班单据计算 则只取加班单据
        //如果当天是按自动生成计算，则只取自动生成的数据
        ITimeScope[] scopeOts = null;//当天某人的加班单
        if (!CollectionUtils.isEmpty(splitVos)) {
            scopeOts = getOtSplitNowDate(splitVos, date, rule).toArray(new OvertimeSplitBillVO[0]);
        }
        //每天的加班单
        if (!ArrayUtils.isEmpty(scopeOts)) {
            for (ITimeScope bill : scopeOts) {
                OvertimeSplitBillVO split = (OvertimeSplitBillVO) bill;
                String type_id = split.getOvertimetypeid();
                BigDecimal splitlength = split.getActuallen();
                if (valueMap.containsKey(type_id)) {//如果已经有该类别了
                    //原来的时长
                    BigDecimal oldLength = new BigDecimal(valueMap.get(type_id).toString());
                    valueMap.put(type_id, oldLength.add(splitlength));

                } else {
                    valueMap.put(type_id, splitlength);
                }

                //处理结算
                if (OvertimeTypeEnum.WORK_TYPE.getIndex().equals(type_id)) {
                    if ("0".equals(rule.getWorkbuchangtype())) {//如果是工作日加班补偿方式是结算加班单
                        if (valueMap.containsKey(OvertimeTypeEnum.WORK_TYPE_JS.getIndex())) {//当天已经有过该结算类别的ID了
                            //原来的时长
                            BigDecimal oldLength = new BigDecimal(valueMap.get(type_id).toString());
                            valueMap.put(OvertimeTypeEnum.WORK_TYPE_JS.getIndex(), oldLength);
                        } else {//当天还没有该结算类别ID
                            valueMap.put(OvertimeTypeEnum.WORK_TYPE_JS.getIndex(), splitlength);
                        }
                    }
                }
                //处理结算
                if (OvertimeTypeEnum.REST_TYPE.getIndex().equals(type_id)) {
                    if ("0".equals(rule.getWorkbuchangtype())) {//如果是工作日加班补偿方式是结算加班单
                        if (valueMap.containsKey(OvertimeTypeEnum.REST_TYPE_JS.getIndex())) {//当天已经有过该结算类别的ID了
                            //原来的时长
                            BigDecimal oldLength = new BigDecimal(valueMap.get(type_id).toString());
                            valueMap.put(OvertimeTypeEnum.REST_TYPE_JS.getIndex(), oldLength);
                        } else {//当天还没有该结算类别ID
                            valueMap.put(OvertimeTypeEnum.REST_TYPE_JS.getIndex(), splitlength);
                        }
                    }
                }
                //处理结算
                if (OvertimeTypeEnum.HOLIDAY_TYPE.getIndex().equals(type_id)) {
                    if ("0".equals(rule.getWorkbuchangtype())) {//如果是工作日加班补偿方式是结算加班单
                        if (valueMap.containsKey(OvertimeTypeEnum.HOLIDAY_TYPE_JS.getIndex())) {//当天已经有过该结算类别的ID了
                            //原来的时长
                            BigDecimal oldLength = new BigDecimal(valueMap.get(type_id).toString());
                            valueMap.put(OvertimeTypeEnum.HOLIDAY_TYPE_JS.getIndex(), oldLength);
                        } else {//当天还没有该结算类别ID
                            valueMap.put(OvertimeTypeEnum.HOLIDAY_TYPE_JS.getIndex(), splitlength);
                        }
                    }
                }

            }
        }
    }


    // 在某人所有加班里找出当天的记录
    private List<OvertimeSplitBillVO> getOtSplitNowDate(List<OvertimeSplitBillVO> list, Date date, OvertimeRule rule) {
        List<OvertimeSplitBillVO> result = new ArrayList<>();

        for (int i = 0; i < list.size(); i++) {
            OvertimeSplitBillVO vo = list.get(i);
            if (new Integer(1).equals(vo.getTransferflag())) {
                continue;
            }
            String type_id = vo.getOvertimetypeid();
            if (OvertimeTypeEnum.WORK_TYPE.getIndex().equals(type_id)) {
                if ("0".equals(rule.getWorkcaltype())) {//如果是工作日加班并且是按自动生成的，则只取来源为自动生成的单据
                    if (0 == vo.getBillsource()) {//来源是加班单
                        continue;
                    }
                } else {
                    if (1 == vo.getBillsource()) {
                        continue;
                    }
                }

            }
            if (OvertimeTypeEnum.REST_TYPE.getIndex().equals(type_id)) {
                if ("0".equals(rule.getRestcaltype())) {//如果是工作日加班并且是按打卡自动生成的，则只取来源为自动生成的单据 0是按打卡1 是按单据
                    if (0 == vo.getBillsource()) {//0是来源为加班单
                        continue;
                    }
                } else {
                    if (1 == vo.getBillsource()) {
                        continue;
                    }
                }

            }
            if (OvertimeTypeEnum.HOLIDAY_TYPE.getIndex().equals(type_id)) {
                if ("0".equals(rule.getHolidaycaltype())) {//如果是工作日加班并且是按自动生成的，则只取来源为自动生成的单据
                    if (0 == vo.getBillsource()) {//
                        continue;
                    }
                } else {
                    if (1 == vo.getBillsource()) {
                        continue;
                    }
                }
            }
            String d = DateUtil.DateToString(vo.getOvertimebegintime(), DateStyle.YYYY_MM_DD);
            if (d.equals(DateUtil.DateToString(date, DateStyle.YYYY_MM_DD))) {
                result.add(vo);
            }
        }
        return result;
    }
}
