package com.kingdee.eas.custom.facade.leave;

import com.google.common.collect.Maps;
import com.grapecity.documents.excel.D;
import com.kingdee.bos.dao.IObjectPK;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
import com.kingdee.bos.metadata.entity.SelectorItemCollection;
import com.kingdee.bos.metadata.entity.SelectorItemInfo;
import com.kingdee.bos.util.BOSUuid;
import com.kingdee.eas.basedata.org.AdminOrgUnitInfo;
import com.kingdee.eas.basedata.org.CtrlUnitInfo;
import com.kingdee.eas.basedata.org.HROrgUnitInfo;
import com.kingdee.eas.basedata.org.PositionInfo;
import com.kingdee.eas.basedata.person.PersonInfo;
import com.kingdee.eas.custom.bd.param.ParamCollection;
import com.kingdee.eas.custom.bd.param.ParamFactory;
import com.kingdee.eas.hr.ats.*;
import com.kingdee.eas.util.app.ContextUtil;
import com.kingdee.shr.base.syssetting.app.osf.OSFAppUtil;
import com.kingdee.util.DateTimeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import com.kingdee.bos.*;
//import com.kingdee.bos.metadata.entity.EntityViewInfo;
//import com.kingdee.bos.dao.IObjectPK;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.framework.CoreBaseCollection;
import com.kingdee.eas.util.app.DbUtil;
import com.kingdee.jdbc.rowset.IRowSet;

/**
 * 假期额度相关后台事务类
 *
 * @author xiaoxin
 */
public class LeaveAllowanceFacadeControllerBean extends AbstractLeaveAllowanceFacadeControllerBean {
    private static Logger logger =
            Logger.getLogger("com.kingdee.eas.custom.facade.leave.LeaveAllowanceFacadeControllerBean");

    // 员工类别 General Administrative Staff
    private static final String WC_General_Administrative_Staff = "General Administrative Staff";
    // 员工类别 Professional Supervisory Staff
    private static final String WC_Professional_Supervisory_Staff = "Professional Supervisory Staff";
    // 员工类别 Senior Administrative Staff
    private static final String WC_Senior_Administrative_Staff = "Senior Administrative Staff";
    private static final String WC_Academic_Staff = "Academic Staff";
    private static final String WC_Others = "Others";
    // 年假初始值 General_Administrative_Staff
    private static final int IV_General_Administrative_Staff = 12;
    // 年假初始值 Professional_Supervisory_Staff
    private static final int IV_Professional_Supervisory_Staff = 15;
    // 年假初始值 Senior_Administrative_Staff
    private static final int IV_Senior_Administrative_Staff = 18;
    private static final int IV_Year = 2;
    private static final int IV_YearAddValue = 1;
    private static final int IV_MAXADD = 8;
    private static final int MONTH_NUM_12 = 12;

    // 年假折算方式
    private static final String PARAM_ANNUALLEAVE_CONVERSIONMETHOD = "param_001";
    // 年假取整方式
    private static final String PARAM_ANNUALLEAVE_INTEGERMETHOD = "param_002";
    // 年假取整精度
    private static final String PARAM_ANNUALLEAVE_INTEGERPERCISION = "param_003";
    // 年假结转日期
    private static final String PARAM_ANNUALLEAVE_CONVERTDATE = "param_004";
    // 生成下年度额度日期
    private static final String PARAM_ANNUALLEAVE_GENERATEDAY = "param_005";
    // 护理假额度
    private static final String PARAM_NURSINGLEAVE_LIMIT = "param_006";
    // 育儿假额度
    private static final String PARAM_PARENTALLEAVE_LIMIT = "param_007";
    // 护理育儿折算方式
    private static final String PARAM_NURSINGANDPARENTALLEAVE_CONVERSIONMETHOD = "param_008";
    // 护理育儿取整方式
    private static final String PARAM_NURSINGANDPARENTALLEAVE_INTEGERMETHOD = "param_009";
    // 护理育儿取整精度
    private static final String PARAM_NURSINGANDPARENTALLEAVE_INTEGERPERCISION = "param_010";
    // 育儿护理多段统计是否更新视图脚本
    private static final String PARAM_NURSINGANDPARENTALLEAVE_UPDATESQL = "param_011";

    // 折算方式 按日
    private static final String CONVERSIONMETHOD_BYDAY = "D";
    // 折算方式 按月
    private static final String CONVERSIONMETHOD_BYMONTH = "M";
    // 取整方式 向上
    private static final String INTEGERMETHOD_UP = "U";
    // 取整方式 向下
    private static final String INTEGERMETHOD_DOWN = "D";
    // 取整精度 0.5
    private static final double INTEGERPERCISION_HALF = 0.5;
    // 取整精度 1
    private static final double INTEGERPERCISION_ONE = 1;

    // 年假折算
    private static String annualLeaveConversionMethod;
    // 年假取整
    private static String annualLeaveIntegerMethod;
    // 年假取整精度
    private static double annualLeaveIntegerPrecision;
    // 结转日期
    private static String annualLeaveConvertDate;
    // 下年度额度生成
    private static String annualLeaveGenerateDay;
    // 育儿假额度
    private static int nursingLeaveLimit;
    // 护理假额度
    private static int parentalLeaveLimit;
    // 护理育儿折算
    private static String nursingAndParentalLeaveConversionMethod;
    // 护理育儿取整
    private static String nursingAndParentalLeaveIntegerMethod;
    // 护理育儿取整精度
    private static double nursingAndParentalLeaveIntegerPrecision;
    // 育儿护理多段统计是否更新视图脚本
    private static String nursingAndParentalLeaveUpdateSql;

    /**
     * 年假额度生成  JQLX000001Y
     */
    @Override
    protected void _createAnnualLeave(Context ctx, int year, String personNum) throws BOSException {
        try {
            // 初始化公共变量
            initialGlobalParam(ctx);

            // 是否生成下年年假额度
            Boolean isGenerateNextYearAnnualLeave = false;

            // 当前时间
            Date currentDate = new Date();
            if (year != 0) {
                currentDate = DateTimeUtils.parseDate(year + "-12-31");
            } else {
                year = DateTimeUtils.getYear(currentDate);
                Date annualLeaveGenerateDay = DateTimeUtils.parseDate(year + "-" + LeaveAllowanceFacadeControllerBean.annualLeaveGenerateDay);
                if (currentDate.getTime() >= annualLeaveGenerateDay.getTime()) {
                    isGenerateNextYearAnnualLeave = true;
                }
            }

            // 年假额度生成
           // generateAnnualLeave(ctx, year, personNum, currentDate);
            Map<String,String> param = Maps.newHashMap();
            param.put("year",String.valueOf(year));
            param.put("personNum",personNum);
            param.put("currentDate",DateTimeUtils.formatDate(currentDate));
            OSFAppUtil.callService(ctx,"leaveAllowanceService",param);
            // 下年年假额度生成
            if (isGenerateNextYearAnnualLeave) {
                int nextYear = year + 1;
                Date nextYearCurrentDay = DateTimeUtils.addYear(currentDate, 1);
               // generateAnnualLeave(ctx, nextYear, personNum, nextYearCurrentDay);
                Map<String,String> nextParam = Maps.newHashMap();
                nextParam.put("year",String.valueOf(nextYear));
                nextParam.put("personNum",personNum);
                nextParam.put("currentDate",DateTimeUtils.formatDate(currentDate));
                OSFAppUtil.callService(ctx,"leaveAllowanceService",nextParam);
            }
        } catch (ParseException | EASBizException e) {
            throw new BOSException(e);
        }

    }

    /**
     * 年假额度生成
     *
     * @param ctx
     * @param year
     * @param personNum
     * @throws BOSException
     */
    private void generateAnnualLeave(Context ctx, int year, String personNum, Date currentDate) throws BOSException {
        try {
            String updateHolidaypolicy = "/*dialect*/MERGE INTO T_HR_ATS_HolidayLimit AS hl \n" +
                    "            USING ( \n" +

                        "            select\n" +
                        "            hl.fid,\n" +
                        "            af.fproposerid, hpf.fid AS holiday_policy_id \n" +
                        "            from \n" +
                        "            T_HR_ATS_AtsHolidayFile af \n" +
                        "            left  JOIN T_HR_ATS_HolidayPolicy hpf ON  hpf.fholidaypolicysetid = af.fholidaypolicysetid \n" +
                        "            left JOIN T_HR_ATS_HolidayType ht ON  ht.FID = hpf.fholidaytypeid \n" +
                        "            left join T_HR_ATS_HolidayLimit hl on af.FPROPOSERID =hl.fproposerid  \n" +
                        "            where ht.FNUMBER = 'JQLX000001Y' and hl.fholidaypolicyid in( \n" +
                        "            select hp.fid from T_HR_ATS_HolidayPolicy hp \n" +
                        "            inner JOIN T_HR_ATS_HolidayType ht ON  ht.FID = hp.fholidaytypeid \n" +
                        "            where ht.FNUMBER = 'JQLX000001Y' \n" +
                        "            ) \n" +
                        "            and to_char(hl.fcyclebegindate,'yyyy')='"+year+"' \n"+
                    "            ) AS src ON hl.fid = src.fid  and to_char(hl.fcyclebegindate,'yyyy') ='"+year+"' \n" +
                    "            WHEN MATCHED THEN \n" +
                    "            UPDATE SET hl.fname_l3=hl.fholidaypolicyid,hl.fholidaypolicyid = src.holiday_policy_id";
            DbUtil.execute(ctx,updateHolidaypolicy);
            Date nowDate = new Date();
            // 考勤制度和年假id对应
            Map<String, String> holidayPolicyMap = new HashMap<String, String>();
            String holidayPolicySql = "select hps.FNUMBER, hp.fid  from T_HR_ATS_HolidayPolicy hp left join T_HR_ATS_HolidayPolicySet hps on hp.FHOLIDAYPOLICYSETID = hps.fid where FHOLIDAYTYPEID = (select fid from T_HR_ATS_HolidayType where FNUMBER = 'JQLX000001Y')";
            IRowSet holidayPolicyRowSet = DbUtil.executeQuery(ctx, holidayPolicySql);
            while (holidayPolicyRowSet.next()) {
                holidayPolicyMap.put(holidayPolicyRowSet.getString("FNUMBER"), holidayPolicyRowSet.getString("fid"));
            }

            String currentDateStr = DateTimeUtils.format(currentDate, "yyyy-MM-dd");
            // 当前年份第一天
            Date yearFirstDay = DateTimeUtils.parseDate(DateTimeUtils.getYear(currentDate) + "-01-01");
            // 当前年份最后一天
            Date yearLastDay = DateTimeUtils.parseDate(DateTimeUtils.getYear(currentDate) + "-12-31");
            List<String> personNumberList = new ArrayList<String>();
            CoreBaseCollection addList = new CoreBaseCollection();
            CoreBaseCollection updateList = new CoreBaseCollection();
            List<String> deleteList = new ArrayList<>();
            // 重算列表
            List<Map<String, Object>> reCalList = new ArrayList<>();
            String personNumStr = "";
            if (StringUtils.isNotEmpty(personNum)) {
                String[] personNumArr = personNum.split(",");
                for (int i = 0; i < personNumArr.length; i++) {
                    personNumberList.add("'" + personNumArr[i] + "'");
                }
                personNumStr = String.join(",", personNumberList);
            }
            String dbType = ContextUtil.getDbType(ctx);

            String sql = " /*dialect*/select * from (select row_number() over (partition by p.fid order by p.fid,eo.feffdt desc,l.fid) as rn,p.fid,p.fnumber," +
                    "eo.FADMINORGID,eo.FHRORGUNITID,eo.FPOSITIONID,p.cfftorptid fullOrPartId,fp.fnumber fullOrPartNumber, p.cffae annualleavelimit," +
                    "case when rbe.fid is null then eo.cfworkercategoryid else rbe.CFWcategoryID end workercategoryid,wc.fname_l2 workercategoryname," +
                    "p.fhiredate, (to_char(to_date('" + currentDateStr + "','yyyy-MM-dd'),'yyyy') - to_char(p.fhiredate,'yyyy')+1)joinDateYear," +
                    "case when rbe.fid is null then null else rbe.FBIZDATE end leaveDate,l.fid limitId,coalesce(l.FADDORSUBLIMIT,0) FADDORSUBLIMIT," +
                    "coalesce(l.FUSEDLIMIT,0) FUSEDLIMIT,coalesce(l.FREEZELIMIT,0) FREEZELIMIT,coalesce(l.cflastcarryforward,0) cflastcarryforward," +
                    "coalesce(l.cfcarryforward,0) cfcarryforward,coalesce(l.CFEntitlementLimit,0) CFEntitlementLimit,coalesce(l.CFInitializedLimit,0) CFInitializedLimit, " +
                    "ebe.FPROBATION,ebe.FPLANFORMALDATE,hp.fid holidayPolicyId,l.fisleftconvert isleftconvert  " +
                    " from T_HR_ATS_AtsHolidayFile f " +
                    " left join T_BD_Person p on f.fproposerid = p.fid " +
                    " left join T_HR_EmpOrgRelation eo on p.fid = eo.fpersonid and eo.fleffdt='2199-12-31 00:00:00' " +
                    " left join CT_MP_Fullorpart fp on fp.fid = p.cfftorptid " +

                    //" left join T_HR_ATS_HolidayPolicySet hps on f.fholidaypolicysetid = hps.fid " +
                    //" left join T_HR_ATS_HolidayPolicy hp on  hp.FHOLIDAYPOLICYSETID = hps.fid " +
                    " left join T_HR_ATS_HolidayType ht on ht.FNUMBER = 'JQLX000001Y'  " +
                    " left join T_HR_ATS_HolidayPolicy hp on  ht.FID =hp.fholidaytypeid " +
                    " and f.fholidaypolicysetid = hp.fholidaypolicysetid " +
                    " left join T_HR_ATS_HolidayLimit l on hp.fid = l.FHOLIDAYPOLICYID and l.FPROPOSERID = p.fid and l.FCYCLEBEGINDATE >= p.fhiredate and l.FCYCLEBEGINDATE <= p.FLEFFDT  and l.fyear =  " + year +
//					" left join T_HR_EmpEnrollBizBillEntry ebe on ebe.FPERSONID = p.fid and ebe.FBIZDATE = p.fhiredate " +
//					" left join T_HR_EmpEnrollBizBill eb on ebe.FBILLID = eb.FID and eb.FBILLSTATE = 3 " +
//					" left join T_HR_ResignBizBillEntry rbe on rbe.FPERSONID = p.fid and p.fhiredate = rbe.FENTERDATE " +
//					" left join T_HR_ResignBizBill rb on rb.fid = rbe.FBILLID and rb.FBILLSTATE = 3 " +

                    " left join ( " +
                    " select rownum rownumber,ebe.FPERSONID, " +
                    " ebe.FPROBATION,ebe.FPLANFORMALDATE, ebe.FBIZDATE " +
                    " from T_HR_EmpEnrollBizBillEntry ebe " +
                    " inner join (select re1.fpersonid,max(re1.fbizdate) fbizdate,count(fid) from T_HR_EmpEnrollBizBillEntry re1 " +
                    " group by re1.fpersonid) re1 on ebe.fpersonid=re1.fpersonid and re1.fbizdate=ebe.fbizdate " +
                    " left join T_HR_EmpEnrollBizBill eb on ebe.FBILLID = eb.FID " +
                    " where eb.FBILLSTATE = 3 " +
                    " order by ebe.fbizdate desc) ebe " +
                    " on ebe.FPERSONID = p.fid " +
                    " and ebe.FBIZDATE = p.fhiredate " +
                    " left join( " +
                    " select rownum rownumber,rbe.fid, rbe.FPERSONID, " +
                    " rbe.FENTERDATE, rbe.CFWcategoryID, rbe.FBIZDATE " +
                    " from T_HR_ResignBizBillEntry rbe " +
                    " inner join (select re1.fpersonid,max(re1.fbizdate) fbizdate,count(fid) from T_HR_ResignBizBillEntry re1 " +
                    " group by re1.fpersonid) re1 on rbe.fpersonid=re1.fpersonid and re1.fbizdate=rbe.fbizdate " +
                    " left join T_HR_ResignBizBill rb on rb.fid = rbe.FBILLID " +
                    " where rb.FBILLSTATE = 3 order by rbe.fbizdate desc " +
                    " ) rbe on  rbe.FPERSONID = p.fid " +
                    " and p.fhiredate = rbe.FENTERDATE " +

                    " left join CT_MP_WorkerCategory wc on (wc.fid = eo.cfworkercategoryid or wc.fid = rbe.CFWcategoryID) " +
                    " where f.fattendfilestate in( 1,2) and ht.FNUMBER = 'JQLX000001Y' and fp.fnumber = 'FULL' and eo.fassigntype = 1 and eo.feffdt <= to_date('" + currentDateStr + "','yyyy-MM-dd') and to_char(p.fhiredate, 'yyyy')<=" + year + " and to_char(p.FLEFFDT,'yyyy')>=" + year + " ";

            if (StringUtils.isNotEmpty(personNumStr)) {
                sql += " and p.fnumber in (" + personNumStr + ")  ";
            }
            sql += " order by l.fid ) temp where temp.rn = 1 ";
            IRowSet iRowSet = DbUtil.executeQuery(ctx, sql);
            while (iRowSet.next()) {
                String holidayPolicyId = iRowSet.getString("holidayPolicyId");
                if (StringUtils.isEmpty(holidayPolicyId)) {
                    holidayPolicyId = holidayPolicyMap.values().stream().findFirst().get();
                    continue;
                }

                String limitId = iRowSet.getString("limitId");
                // 教师年假额度
                int annualleavelimit = iRowSet.getInt("annualleavelimit");
                // 员工类别
                String workercategoryname = iRowSet.getString("workercategoryname");
                // 司龄
                int joinDateYear = iRowSet.getInt("joinDateYear");
                // 入职日期
                Date joinDate = iRowSet.getDate("fhiredate");
                 Date fplanformaldate = iRowSet.getDate("FPLANFORMALDATE");
                // 离职日期
                 Date leaveDate = iRowSet.getDate("leaveDate");
                // 标准额度=额度规则（折算额度）+初始化额度+从去年结转-结转到明年
                BigDecimal standardLimit = BigDecimal.ZERO;
                // 折算标准额度
                BigDecimal convertedLimit = BigDecimal.ZERO;
                // 未折算标准额度
                BigDecimal entitlementLimit = BigDecimal.ZERO;
                //是否离职折算过
                int isLeave = 0;
                // 实际额度
                BigDecimal realLimit = BigDecimal.ZERO;
                // 剩余额度
                BigDecimal remainLimit = BigDecimal.ZERO;
                // 未折算标准额度
                BigDecimal entitlementLimitOld = iRowSet.getBigDecimal("CFEntitlementLimit");
                // 初始化额度
                BigDecimal initializedLimit = iRowSet.getBigDecimal("CFInitializedLimit");
                // 从去年结转额度
                BigDecimal lastCarryforward = iRowSet.getBigDecimal("CFLastCarryforward");
                // 结转到明年
                BigDecimal carryforward = iRowSet.getBigDecimal("CFCarryforward");
                // 增减额度
                BigDecimal addOrSubLimit = iRowSet.getBigDecimal("FADDORSUBLIMIT");
                // 已用额度
                BigDecimal usedLimit = iRowSet.getBigDecimal("FUSEDLIMIT");
                // 在途额度
                BigDecimal freezeLimit = iRowSet.getBigDecimal("FreezeLimit");
                //是否离职折算
                int isleftconvert = iRowSet.getInt("isleftconvert");

                // 全职行政人员额度规则
                if (StringUtils.equalsIgnoreCase(workercategoryname, WC_General_Administrative_Staff)
                        || StringUtils.equalsIgnoreCase(workercategoryname, WC_Professional_Supervisory_Staff)
                        || StringUtils.equalsIgnoreCase(workercategoryname, WC_Senior_Administrative_Staff)) {
                    if (annualleavelimit > 0) {
                        // 如果员工信息-教师年假额度中数值>0,则取值员工信息-教师年假额度值，司龄每满两年加一天，最多加八天(最大值30天)
                        convertedLimit = BigDecimal.valueOf(annualleavelimit + (joinDateYear - 1) / IV_Year * IV_YearAddValue);
                        if (convertedLimit.compareTo(BigDecimal.valueOf(30)) > 0) {
                            convertedLimit = BigDecimal.valueOf(30);
                        }
                    } else {
                        // 员工类别=General Administrative Staff，则初始值为12，司龄每满两年加一天，最多加八天；
                        if (StringUtils.equalsIgnoreCase(workercategoryname, WC_General_Administrative_Staff)) {
                            convertedLimit = BigDecimal.valueOf(IV_General_Administrative_Staff + (joinDateYear - 1) / IV_Year * IV_YearAddValue);
                            if (convertedLimit.compareTo(BigDecimal.valueOf(IV_General_Administrative_Staff + IV_MAXADD)) > 0) {
                                convertedLimit = BigDecimal.valueOf(IV_General_Administrative_Staff + IV_MAXADD);
                            }
                        }

                        // 员工类别=Professional Supervisory Staff，则初始值为15，司龄每满两年加一天，最多加八天；
                        if (StringUtils.equalsIgnoreCase(workercategoryname, WC_Professional_Supervisory_Staff)) {
                            convertedLimit = BigDecimal.valueOf(IV_Professional_Supervisory_Staff + (joinDateYear - 1) / IV_Year * IV_YearAddValue);
                            if (convertedLimit.compareTo(BigDecimal.valueOf(IV_Professional_Supervisory_Staff + IV_MAXADD)) > 0) {
                                convertedLimit = BigDecimal.valueOf(IV_Professional_Supervisory_Staff + IV_MAXADD);
                            }
                        }

                        // 员工类别=Senior Administrative Staff，则初始值为18，司龄每满两年加一天，最多加八天；
                        if (StringUtils.equalsIgnoreCase(workercategoryname, WC_Senior_Administrative_Staff)) {
                            convertedLimit = BigDecimal.valueOf(IV_Senior_Administrative_Staff + (joinDateYear - 1) / IV_Year * IV_YearAddValue);
                            if (convertedLimit.compareTo(BigDecimal.valueOf(IV_Senior_Administrative_Staff + IV_MAXADD)) > 0) {
                                convertedLimit = BigDecimal.valueOf(IV_Senior_Administrative_Staff + IV_MAXADD);
                            }
                        }
                    }
                } else if (StringUtils.equalsIgnoreCase(workercategoryname, WC_Academic_Staff)
                        || StringUtils.equalsIgnoreCase(workercategoryname, WC_Others)) {
                    // 全职学术人员和全职其他人员
                    // 取值员工信息-教师年假额度字段
                    convertedLimit = BigDecimal.valueOf(annualleavelimit);
                }
                // 未折算标准额度
                entitlementLimit = convertedLimit;

                // 离职折算
                if (leaveDate != null && DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(leaveDate) && (joinDate.compareTo(leaveDate) < 0)) {
                    if (StringUtils.equals(CONVERSIONMETHOD_BYDAY, annualLeaveConversionMethod)) {
                        // TODO 暂时使按月折算的逻辑
                        if (DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(joinDate)) {
                            convertedLimit = convertedLimit.multiply(BigDecimal.valueOf(DateTimeUtils.getMonth(leaveDate) - DateTimeUtils.getMonth(joinDate) + 1)).divide(BigDecimal.valueOf(MONTH_NUM_12), 10, BigDecimal.ROUND_HALF_UP);
                        } else {
                            convertedLimit = convertedLimit.multiply(BigDecimal.valueOf(DateTimeUtils.getMonth(leaveDate))).divide(BigDecimal.valueOf(MONTH_NUM_12), 10, BigDecimal.ROUND_HALF_UP);
                        }
                    } else {
                        if (DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(joinDate)) {
                            convertedLimit = convertedLimit.multiply(BigDecimal.valueOf(DateTimeUtils.getMonth(leaveDate) - DateTimeUtils.getMonth(joinDate) + 1)).divide(BigDecimal.valueOf(MONTH_NUM_12), 10, BigDecimal.ROUND_HALF_UP);
                        } else {
                            convertedLimit = convertedLimit.multiply(BigDecimal.valueOf(DateTimeUtils.getMonth(leaveDate))).divide(BigDecimal.valueOf(MONTH_NUM_12), 10, BigDecimal.ROUND_HALF_UP);
                        }
                    }
                } else {
                    // 入职折算,是当前年入职的，且离职日期小于入职日期
                    if (DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(joinDate)) {
                        if (StringUtils.equals(CONVERSIONMETHOD_BYDAY, annualLeaveConversionMethod)) {
                            // TODO 暂时使用按月折算的逻辑
                            convertedLimit = convertedLimit.multiply(BigDecimal.valueOf(MONTH_NUM_12 - DateTimeUtils.getMonth(joinDate) + 1)).divide(BigDecimal.valueOf(MONTH_NUM_12), 10, BigDecimal.ROUND_HALF_UP);
                        } else {
                            convertedLimit = convertedLimit.multiply(BigDecimal.valueOf(MONTH_NUM_12 - DateTimeUtils.getMonth(joinDate) + 1)).divide(BigDecimal.valueOf(MONTH_NUM_12), 10, BigDecimal.ROUND_HALF_UP);
                        }
                    }
                }

                // 年假取整
                // 整数部分
                BigDecimal standardLimitInteger = convertedLimit.setScale(0, RoundingMode.FLOOR);
                // 小数部分
                BigDecimal standardLimitDecimal = convertedLimit.subtract(standardLimitInteger);
                if (Double.doubleToLongBits(INTEGERPERCISION_HALF) == Double.doubleToLongBits(annualLeaveIntegerPrecision)) {
                    if (StringUtils.equals(INTEGERMETHOD_UP, annualLeaveIntegerMethod)) {
                        if (standardLimitDecimal.compareTo(BigDecimal.valueOf(0.5)) > 0) {
                            convertedLimit = convertedLimit.setScale(0, RoundingMode.CEILING);
                        } else if (standardLimitDecimal.compareTo(BigDecimal.ZERO) > 0) {
                            convertedLimit = standardLimitInteger.add(BigDecimal.valueOf(0.5));
                        } else {
                            convertedLimit = standardLimitInteger;
                        }
                    } else {
                        if (standardLimitDecimal.compareTo(BigDecimal.valueOf(0.5)) > 0) {
                            convertedLimit = standardLimitInteger.add(BigDecimal.valueOf(0.5));
                        } else {
                            convertedLimit = convertedLimit.setScale(0, RoundingMode.FLOOR);
                        }
                    }
                } else {
                    if (StringUtils.equals(INTEGERMETHOD_UP, annualLeaveIntegerMethod)) {
                        convertedLimit = convertedLimit.setScale(0, RoundingMode.CEILING);
                    } else {
                        convertedLimit = convertedLimit.setScale(0, RoundingMode.FLOOR);
                    }
                }
                // 未折算标准额度
                if (entitlementLimit.compareTo(entitlementLimitOld) != 0 && year <= DateTimeUtils.getYear(nowDate)) {
                    lastCarryforward = BigDecimal.ZERO;
                    Map<String, Object> param = new HashMap<>();
                    param.put("year", year);
                    param.put("personNum", iRowSet.getString("fnumber"));
                    reCalList.add(param);
                }

                // 标准额度 = 额度规则（折算额度）+初始化额度+从去年结转-结转到明年
                standardLimit = convertedLimit.add(initializedLimit).add(lastCarryforward).subtract(carryforward);
                // 实际额度 = 标准额度+增减额度
                realLimit = standardLimit.add(addOrSubLimit);
                // 剩余额度 = 实际额度-已用额度-在途额度
                remainLimit = realLimit.subtract(usedLimit).subtract(freezeLimit);
                BigDecimal addOrSub=BigDecimal.ZERO;
                if(remainLimit.compareTo(BigDecimal.valueOf(30))>0){
                    addOrSub = BigDecimal.valueOf(30).subtract(remainLimit);

                }
                if (StringUtils.isNotEmpty(limitId)) {
                    HolidayLimitInfo holidayLimitInfo = new HolidayLimitInfo();
                    holidayLimitInfo.setId(BOSUuid.read(limitId));
                    // 标准额度
                    holidayLimitInfo.setStandardLimit(standardLimit);
                    //增减
                    addOrSubLimit=addOrSubLimit.add(addOrSub);
                    holidayLimitInfo.setAddOrSubLimit(addOrSubLimit);
                    // 折算标准额度
                    holidayLimitInfo.setBigDecimal("convertedLimit", convertedLimit);
                    // 未折算标准额度
                    holidayLimitInfo.setBigDecimal("entitlementLimit", entitlementLimit);
                    holidayLimitInfo.setRealLimit(realLimit);
                    holidayLimitInfo.setRemainLimit(remainLimit);
                    holidayLimitInfo.setBigDecimal("lastCarryforward", lastCarryforward);
                    holidayLimitInfo.setBigDecimal("Carryforward", carryforward);
                    // 默认值
//                    holidayLimitInfo.setCycleBeginDate(yearFirstDay);
//                    holidayLimitInfo.setCycleEndDate(yearLastDay);
//                    holidayLimitInfo.setEffectDate(yearFirstDay);
//                    holidayLimitInfo.setDelayDate(yearLastDay);

                    // 离职情况
                    if (leaveDate != null && DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(leaveDate) && joinDate.compareTo(leaveDate) < 0) {
                        holidayLimitInfo.setCycleEndDate(leaveDate);
                        holidayLimitInfo.setDelayDate(leaveDate);
                        holidayLimitInfo.setIsLeftConvert(true);
                    }else {
                        // 入职情况
                        if (DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(joinDate)) {
                            holidayLimitInfo.setCycleBeginDate(joinDate);
                            int fprobation = iRowSet.getInt("FPROBATION");
                            if (fprobation > 0) {
                                holidayLimitInfo.setEffectDate(iRowSet.getDate("FPLANFORMALDATE"));
                            } else {
                                holidayLimitInfo.setEffectDate(holidayLimitInfo.getCycleBeginDate());
                            }
                        }
                        holidayLimitInfo.setIsLeftConvert(false);
//                        else if ((fplanformaldate != null && DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(fplanformaldate))) {
//                            int fprobation = iRowSet.getInt("FPROBATION");
//                            if (fprobation > 0) {
//                                holidayLimitInfo.setEffectDate(iRowSet.getDate("FPLANFORMALDATE"));
//                            } else {
//                                holidayLimitInfo.setEffectDate(holidayLimitInfo.getCycleBeginDate());
//                            }
//                        }
                    }
                    if (StringUtils.isNotEmpty(iRowSet.getString("FADMINORGID"))) {
                        AdminOrgUnitInfo adminOrgUnitInfo = new AdminOrgUnitInfo();
                        adminOrgUnitInfo.setId(BOSUuid.read(iRowSet.getString("FADMINORGID")));
                        holidayLimitInfo.setAdminOrgUnit(adminOrgUnitInfo);
                    }
                    if (StringUtils.isNotEmpty(iRowSet.getString("FPOSITIONID"))) {
                        PositionInfo positionInfo = new PositionInfo();
                        positionInfo.setId(BOSUuid.read(iRowSet.getString("FPOSITIONID")));
                        holidayLimitInfo.setPosition(positionInfo);
                    }
                    holidayLimitInfo.setLastUpdateUser(ContextUtil.getCurrentUserInfo(ctx));
                    holidayLimitInfo.setLastUpdateTime(new Timestamp(nowDate.getTime()));
                    // 如果假期额度在离职日期之后，且是离职折算后的，不生成
                    if (leaveDate != null && 1 == isleftconvert && leaveDate.getTime() <= holidayLimitInfo.getCycleEndDate().getTime()) {
                        //deleteList.add(limitId);
                        continue;
                    }else {

                        updateList.add(holidayLimitInfo);
                    }
                } else {
                    HolidayLimitInfo holidayLimitInfo = new HolidayLimitInfo();
                    holidayLimitInfo.setStandardLimit(standardLimit);
                    holidayLimitInfo.setBigDecimal("convertedLimit", convertedLimit);
                    holidayLimitInfo.setBigDecimal("entitlementLimit", entitlementLimit);

                    holidayLimitInfo.setRealLimit(realLimit);
                    holidayLimitInfo.setRemainLimit(remainLimit);
                    holidayLimitInfo.setFreezeLimit(BigDecimal.ZERO);
                    holidayLimitInfo.setUsedLimit(BigDecimal.ZERO);
                    holidayLimitInfo.setAddOrSubLimit(addOrSub);
                    holidayLimitInfo.setPreOverdraftLimit(BigDecimal.ZERO);
                    if (DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(joinDate)) {
                        holidayLimitInfo.setCycleBeginDate(joinDate);
                        int fprobation = iRowSet.getInt("FPROBATION");
                        if (fprobation > 0) {
                            holidayLimitInfo.setEffectDate(iRowSet.getDate("FPLANFORMALDATE"));
                        } else {
                            holidayLimitInfo.setEffectDate(holidayLimitInfo.getCycleBeginDate());
                        }
                    } else if ((fplanformaldate != null && DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(fplanformaldate))) {
                        holidayLimitInfo.setCycleBeginDate(yearFirstDay);
                        int fprobation = iRowSet.getInt("FPROBATION");
                        if (fprobation > 0) {
                            holidayLimitInfo.setEffectDate(iRowSet.getDate("FPLANFORMALDATE"));
                        } else {
                            holidayLimitInfo.setEffectDate(holidayLimitInfo.getCycleBeginDate());
                        }
                    } else {
                        holidayLimitInfo.setCycleBeginDate(yearFirstDay);
                        holidayLimitInfo.setEffectDate(holidayLimitInfo.getCycleBeginDate());
                    }
                    // 离职情况
                    if (leaveDate != null && DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(leaveDate)) {
                        holidayLimitInfo.setCycleEndDate(leaveDate);
                        holidayLimitInfo.setDelayDate(leaveDate);
                        holidayLimitInfo.setIsLeftConvert(true);
                    } else {
                        holidayLimitInfo.setCycleEndDate(yearLastDay);
                        holidayLimitInfo.setDelayDate(yearLastDay);
                    }

                    holidayLimitInfo.setYear(DateTimeUtils.getYear(yearFirstDay));
                    HolidayPolicyInfo holidayPolicyInfo = new HolidayPolicyInfo();
                    holidayPolicyInfo.setId(BOSUuid.read(holidayPolicyId));
                    holidayLimitInfo.setHolidayPolicy(holidayPolicyInfo);
                    holidayLimitInfo.setHolidayUnit(HolidayTypeUnitEnum.day);
                    holidayLimitInfo.setEnableCycle(true);
                    PersonInfo personInfo = new PersonInfo();
                    personInfo.setId(BOSUuid.read(iRowSet.getString("fid")));
                    holidayLimitInfo.setProposer(personInfo);
                    holidayLimitInfo.setStatus(HolidayLimitStatus.audited);
                    if (StringUtils.isNotEmpty(iRowSet.getString("FADMINORGID"))) {
                        AdminOrgUnitInfo adminOrgUnitInfo = new AdminOrgUnitInfo();
                        adminOrgUnitInfo.setId(BOSUuid.read(iRowSet.getString("FADMINORGID")));
                        holidayLimitInfo.setAdminOrgUnit(adminOrgUnitInfo);
                    }

                    if (StringUtils.isNotEmpty(iRowSet.getString("FHRORGUNITID"))) {
                        HROrgUnitInfo hrOrgUnitInfo = new HROrgUnitInfo();
                        hrOrgUnitInfo.setId(BOSUuid.read(iRowSet.getString("FHRORGUNITID")));
                        holidayLimitInfo.setHrOrgUnit(hrOrgUnitInfo);
                    }
                    if (StringUtils.isNotEmpty(iRowSet.getString("FPOSITIONID"))) {
                        PositionInfo positionInfo = new PositionInfo();
                        positionInfo.setId(BOSUuid.read(iRowSet.getString("FPOSITIONID")));
                        holidayLimitInfo.setPosition(positionInfo);
                    }

                    CtrlUnitInfo ctrlUnitInfo = new CtrlUnitInfo();
                    ctrlUnitInfo.setId(BOSUuid.read("00000000-0000-0000-0000-000000000000CCE7AED4"));
                    holidayLimitInfo.setCU(ctrlUnitInfo);
                    holidayLimitInfo.setCycleDate(yearLastDay);
                    holidayLimitInfo.setCreator(ContextUtil.getCurrentUserInfo(ctx));
                    holidayLimitInfo.setCreateTime(new Timestamp(nowDate.getTime()));
                    holidayLimitInfo.setLastUpdateUser(ContextUtil.getCurrentUserInfo(ctx));
                    holidayLimitInfo.setLastUpdateTime(new Timestamp(nowDate.getTime()));
                    // 如果假期额度在离职日期之后，不生成
                    if (leaveDate != null && 1 == isleftconvert && leaveDate.getTime() <= holidayLimitInfo.getCycleEndDate().getTime()) {
                        continue;
                    }else {

                        addList.add(holidayLimitInfo);
                    }
                }
            }
            if (addList.size() > 0) {
                HolidayLimitFactory.getLocalInstance(ctx).addnewBatchData(addList);
            }
            if (updateList.size() > 0) {
                HolidayLimitFactory.getLocalInstance(ctx).updateBatchData(updateList);
            }
            if (deleteList.size() > 0) {
                IObjectPK[] iObjectPKS = new IObjectPK[deleteList.size()];
                for (int i = 0; i < deleteList.size(); i++) {
                    iObjectPKS[i] = new ObjectUuidPK(deleteList.get(i));
                }
                HolidayLimitFactory.getLocalInstance(ctx).deleteBatchData(iObjectPKS);
            }
            if (reCalList.size() > 0) {
                for (int i = 0; i < reCalList.size(); i++) {
                    int yearP = (int) reCalList.get(i).get("year");
                    String personNumP = (String) reCalList.get(i).get("personNum");
                    String lastYearSql = "/*dialect*/select p.fid,l.fid limitId,l.FSTANDARDLIMIT,l.FADDORSUBLIMIT,l.FUSEDLIMIT,l.FREEZELIMIT, coalesce(l.CFInitializedLimit, 0) CFInitializedLimit,coalesce(l.CFConvertedLimit, 0) CFConvertedLimit, coalesce(l.cflastcarryforward,0) cflastcarryforward,coalesce(l.cfcarryforward,0) cfcarryforward from t_bd_person p\n" +
                            " left join T_HR_ATS_AtsHolidayFile f on f.fproposerid = p.fid  \n" +
                            " left join T_HR_ATS_HolidayPolicySet hps on f.fholidaypolicysetid = hps.fid  \n" +
                            " left join T_HR_ATS_HolidayPolicy hp on  hps.fid = hp.fholidaypolicysetid \n" +
                            " left join T_HR_ATS_HolidayType ht on ht.FNUMBER = 'JQLX000001Y' and ht.fid = hp.FHOLIDAYTYPEID  \n" +

                            " left join T_HR_ATS_HolidayLimit l on hp.fid = l.FHOLIDAYPOLICYID and l.FPROPOSERID = p.fid and  l.FCYCLEBEGINDATE >= p.fhiredate and l.FCYCLEBEGINDATE <= p.FLEFFDT and l.fyear =  " + (yearP - 1) + "\n" +
                            " where f.fattendfilestate = 1 and p.fnumber = '" + personNumP + "' and l.fid is not null and ht.FNUMBER = 'JQLX000001Y' ";
                    if (StringUtils.equalsIgnoreCase("MS SQL Server", dbType)) {
                        lastYearSql = "/*dialect*/select p.fid,l.fid limitId,l.FSTANDARDLIMIT,l.FADDORSUBLIMIT,l.FUSEDLIMIT,l.FREEZELIMIT, isnull(l.CFInitializedLimit, 0) CFInitializedLimit,isnull(l.CFConvertedLimit, 0) CFConvertedLimit, isnull(l.cflastcarryforward,0) cflastcarryforward,isnull(l.cfcarryforward,0) cfcarryforward from t_bd_person p\n" +
                                " left join T_HR_ATS_AtsHolidayFile f on f.fproposerid = p.fid  \n" +
                                " left join T_HR_ATS_HolidayPolicySet hps on f.fholidaypolicysetid = hps.fid  \n" +
                                " left join T_HR_ATS_HolidayPolicy hp on hps.fid = hp.fholidaypolicysetid \n" +
                                " left join T_HR_ATS_HolidayType ht on ht.FNUMBER = 'JQLX000001Y' and ht.fid = hp.FHOLIDAYTYPEID  \n" +

                                " left join T_HR_ATS_HolidayLimit l on hp.fid = l.FHOLIDAYPOLICYID and l.FPROPOSERID = p.fid and  l.FCYCLEBEGINDATE >= p.fhiredate and l.FCYCLEBEGINDATE <= p.FLEFFDT and l.fyear =  " + (yearP - 1) + "\n" +
                                " where f.fattendfilestate = 1 and p.fnumber = '" + personNumP + "' and l.fid is not null and ht.FNUMBER = 'JQLX000001Y'  ";
                    }

                    IRowSet lastYearRowSet = DbUtil.executeQuery(ctx, lastYearSql);
                    if (lastYearRowSet.next()) {
                        HolidayLimitInfo lastYearHolidayLimitInfo = new HolidayLimitInfo();
                        // 标准额度 = 额度规则（折算额度）+初始化额度+从去年结转-结转到明年
                        BigDecimal lastYearConvertedLimit = lastYearRowSet.getBigDecimal("CFConvertedLimit");
                        BigDecimal lastYearInitializedLimit = lastYearRowSet.getBigDecimal("CFInitializedLimit");
                        BigDecimal lastYearLastCarryforward = lastYearRowSet.getBigDecimal("CFLastCarryforward");
                        BigDecimal lastYearCarryforward = BigDecimal.ZERO;
                        BigDecimal lastYearStandardLimit = lastYearConvertedLimit.add(lastYearInitializedLimit).add(lastYearLastCarryforward).subtract(lastYearCarryforward);
                        lastYearHolidayLimitInfo.setId(BOSUuid.read(lastYearRowSet.getString("limitId")));
                        //lastYearHolidayLimitInfo.setStandardLimit(lastYearStandardLimit);
                        //lastYearHolidayLimitInfo.setRealLimit(lastYearHolidayLimitInfo.getStandardLimit().add(lastYearRowSet.getBigDecimal("FADDORSUBLIMIT")));
                        //lastYearHolidayLimitInfo.setRemainLimit(lastYearHolidayLimitInfo.getRealLimit().subtract(lastYearRowSet.getBigDecimal("FUSEDLIMIT")).subtract(lastYearRowSet.getBigDecimal("FreezeLimit")));
                        lastYearHolidayLimitInfo.setBigDecimal("Carryforward", lastYearCarryforward);
                        lastYearHolidayLimitInfo.setLastUpdateUser(ContextUtil.getCurrentUserInfo(ctx));
                        lastYearHolidayLimitInfo.setLastUpdateTime(new Timestamp(nowDate.getTime()));
                        //todo 历史额度不能变
                        //HolidayLimitFactory.getLocalInstance(ctx).updatePartial(new ObjectUuidPK(lastYearHolidayLimitInfo.getId()), lastYearHolidayLimitInfo);
                        LeaveAllowanceFacadeFactory.getLocalInstance(ctx).carryForwardLeave(yearP, true, personNumP);
                    }
                }
            }
        } catch (SQLException e) {
            throw new BOSException(e);
        } catch (ParseException e) {
            throw new BOSException(e);
        } catch (EASBizException e) {
            throw new BOSException(e);
        }
    }

    private void initialGlobalParam(Context ctx) throws BOSException {
        // 全局变量
        Map<String, String> param = new HashMap<String, String>();
        ParamCollection paramCollection = ParamFactory.getLocalInstance(ctx).getParamCollection();
        for (int i = 0; i < paramCollection.size(); i++) {
            param.put(paramCollection.get(i).getNumber(), paramCollection.get(i).getValue());
        }
        // 年假折算
        annualLeaveConversionMethod = param.get(PARAM_ANNUALLEAVE_CONVERSIONMETHOD);
        // 年假取整
        annualLeaveIntegerMethod = param.get(PARAM_ANNUALLEAVE_INTEGERMETHOD);
        // 年假取整精度
        annualLeaveIntegerPrecision = Double.valueOf(param.get(PARAM_ANNUALLEAVE_INTEGERPERCISION));
        // 结转日期
        annualLeaveConvertDate = param.get(PARAM_ANNUALLEAVE_CONVERTDATE);
        // 下年度额度生成
        annualLeaveGenerateDay = param.get(PARAM_ANNUALLEAVE_GENERATEDAY);
        // 育儿假额度
        nursingLeaveLimit = Integer.parseInt(param.get(PARAM_NURSINGLEAVE_LIMIT));
        // 护理假额度
        parentalLeaveLimit = Integer.parseInt(param.get(PARAM_PARENTALLEAVE_LIMIT));
        // 护理育儿折算
        nursingAndParentalLeaveConversionMethod = param.get(PARAM_NURSINGANDPARENTALLEAVE_CONVERSIONMETHOD);
        // 护理育儿取整
        nursingAndParentalLeaveIntegerMethod = param.get(PARAM_NURSINGANDPARENTALLEAVE_INTEGERMETHOD);
        // 护理育儿取整精度
        nursingAndParentalLeaveIntegerPrecision = Double.valueOf(param.get(PARAM_NURSINGANDPARENTALLEAVE_INTEGERPERCISION));
        // 育儿护理多段统计是否更新视图脚本
        nursingAndParentalLeaveUpdateSql = param.get(PARAM_NURSINGANDPARENTALLEAVE_UPDATESQL);
    }


    /**
     * 设置司龄
     */
    @Override
    public void setSeniority(Context ctx) throws BOSException, EASBizException {
        String hisSql = "update T_HR_PersonPositionHis set FJOINCOMPANYYEARS=CEILING(FJOINCOMPANYYEARS) where year(FJOINDATE)<year(now())";
        logger.error("设置司龄SQL(HIS)：" + hisSql);
        DbUtil.execute(ctx, hisSql);

        String sql = "update T_HR_PersonPosition set FJOINCOMPANYYEARS=CEILING(FJOINCOMPANYYEARS) where year(FJOINDATE)<year(now())";
        logger.error("设置司龄SQL：" + sql);
        DbUtil.execute(ctx, sql);
    }

    /**
     * 年假结转
     */
    @Override
    protected void _carryForwardLeave(Context ctx, int year, boolean isExecute, String personNum) throws BOSException, EASBizException {

        try {
            if (!isExecute) {
                return;
            }
            // 初始化公共变量
            initialGlobalParam(ctx);
            // 当前时间
            Date nowDate = new Date();
            Date currentDate = new Date();
            if (year != 0) {
                currentDate = DateTimeUtils.parseDate(year + "-12-31");
            } else {
                year = DateTimeUtils.getYear(currentDate);
            }
            List<String> personNumberList = new ArrayList<String>();
            CoreBaseCollection lastYearList = new CoreBaseCollection();
            CoreBaseCollection thisYearList = new CoreBaseCollection();
            String personNumStr = "";
            if (StringUtils.isNotEmpty(personNum)) {
                String[] personNumArr = personNum.split(",");
                for (int i = 0; i < personNumArr.length; i++) {
                    personNumberList.add("'" + personNumArr[i] + "'");
                }
                personNumStr = String.join(",", personNumberList);
            }
            Date annualLeaveConvertDate = DateTimeUtils.parseDate(year + "-" + LeaveAllowanceFacadeControllerBean.annualLeaveConvertDate);
            if (currentDate.getTime() >= annualLeaveConvertDate.getTime()) {

                String sql = " /*dialect*/select thisL.fid thisLFid, lastL.fid lastLfID,thisL.FSTANDARDLIMIT, lastL.FREMAINLIMIT,ht.FNUMBER, " +
                        " case when lastL.FREMAINLIMIT + thisL.CFEntitlementLimit <= 30 then coalesce(lastL.FREMAINLIMIT,0) else coalesce(30 - thisL.CFEntitlementLimit,0) end lastnextForward,  " +
                        " case when lastL.FREMAINLIMIT + thisL.CFEntitlementLimit <= 30 then coalesce(lastL.FREMAINLIMIT,0) else coalesce(30 - thisL.CFEntitlementLimit,0) end thislastforward,  " +
                        " lastL.FStandardLimit lFStandardLimit,coalesce(lastL.cfinitializedlimit,0) lcfinitializedlimit,coalesce(lastL.cfconvertedlimit,0) lcfconvertedlimit,lastL.FADDORSUBLIMIT lFADDORSUBLIMIT,lastL.FUSEDLIMIT lFUSEDLIMIT,lastL.FREEZELIMIT lFREEZELIMIT,coalesce(lastL.cflastcarryforward,0) lcflastcarryforward,coalesce(lastL.cfcarryforward,0) lcfcarryforward, " +
                        " thisL.FStandardLimit tFStandardLimit,coalesce(thisL.cfinitializedlimit,0) tcfinitializedlimit,coalesce(thisL.cfconvertedlimit,0) tcfconvertedlimit,thisL.FADDORSUBLIMIT tFADDORSUBLIMIT,thisL.FUSEDLIMIT tFUSEDLIMIT,thisL.FREEZELIMIT tFREEZELIMIT,coalesce(thisL.cflastcarryforward,0) tcflastcarryforward,coalesce(thisL.cfcarryforward,0) tcfcarryforward " +
                        " from t_bd_person p  " +
                        " left join T_HR_ATS_HolidayLimit lastL on p.fid = lastL.FPROPOSERID and lastL.FCYCLEBEGINDATE >= p.fhiredate and lastL.FCYCLEBEGINDATE <= p.FLEFFDT " +
                        " left join T_HR_ATS_HolidayLimit thisL on thisL.FHOLIDAYPOLICYID = lastL.FHOLIDAYPOLICYID and thisL.FPROPOSERID = lastL.FPROPOSERID  and thisL.FCYCLEBEGINDATE >= p.fhiredate and thisL.FCYCLEBEGINDATE <= p.FLEFFDT " +
                        " left join T_HR_ATS_AtsHolidayFile hf on hf.fproposerid = p.fid  " +
                        " left join T_HR_ATS_HolidayPolicySet hps on hf.fholidaypolicysetid = hps.fid     " +
                        " left join T_HR_ATS_HolidayPolicy hp on  hps.fid = hp.fholidaypolicysetid and thisL.FHOLIDAYPOLICYID = hp.fid  " +
                        " left join T_HR_ATS_HolidayType ht on ht.fid = hp.FHOLIDAYTYPEID and ht.FNUMBER = 'JQLX000001Y'     " +
                        " where  hf.fattendfilestate = 1 and ht.FNUMBER = 'JQLX000001Y' and (lastL.cfcarryforward is null or lastL.cfcarryforward = 0) and thisL.FYEAR = " + year + " and lastL.fyear = " + (year - 1) + "";

                String dbType = ContextUtil.getDbType(ctx);
                if (StringUtils.equalsIgnoreCase("MS SQL Server", dbType)) {
                    sql = " /*dialect*/select thisL.fid thisLFid, lastL.fid lastLfID,thisL.FSTANDARDLIMIT, lastL.FREMAINLIMIT,ht.FNUMBER, " +
                            " case when lastL.FREMAINLIMIT + thisL.CFEntitlementLimit <= 30 then isnull(lastL.FREMAINLIMIT,0) else isnull(30 - thisL.CFEntitlementLimit,0) end lastnextForward,  " +
                            " case when lastL.FREMAINLIMIT + thisL.CFEntitlementLimit <= 30 then isnull(lastL.FREMAINLIMIT,0) else isnull(30 - thisL.CFEntitlementLimit,0) end thislastforward,  " +
                            " lastL.FStandardLimit lFStandardLimit,isnull(lastL.cfinitializedlimit,0) lcfinitializedlimit,isnull(lastL.cfconvertedlimit,0) lcfconvertedlimit,lastL.FADDORSUBLIMIT lFADDORSUBLIMIT,lastL.FUSEDLIMIT lFUSEDLIMIT,lastL.FREEZELIMIT lFREEZELIMIT,isnull(lastL.cflastcarryforward,0) lcflastcarryforward,isnull(lastL.cfcarryforward,0) lcfcarryforward, " +
                            " thisL.FStandardLimit tFStandardLimit,isnull(thisL.cfinitializedlimit,0) tcfinitializedlimit,isnull(thisL.cfconvertedlimit,0) tcfconvertedlimit,thisL.FADDORSUBLIMIT tFADDORSUBLIMIT,thisL.FUSEDLIMIT tFUSEDLIMIT,thisL.FREEZELIMIT tFREEZELIMIT,isnull(thisL.cflastcarryforward,0) tcflastcarryforward,isnull(thisL.cfcarryforward,0) tcfcarryforward " +
                            " from t_bd_person p  " +
                            " left join T_HR_ATS_HolidayLimit lastL on p.fid = lastL.FPROPOSERID  and lastL.FCYCLEBEGINDATE >= p.fhiredate and lastL.FCYCLEBEGINDATE <= p.FLEFFDT " +
                            " left join T_HR_ATS_HolidayLimit thisL on thisL.FHOLIDAYPOLICYID = lastL.FHOLIDAYPOLICYID and thisL.FPROPOSERID = lastL.FPROPOSERID   and thisL.FCYCLEBEGINDATE >= p.fhiredate and thisL.FCYCLEBEGINDATE <= p.FLEFFDT  " +
                            " left join T_HR_ATS_AtsHolidayFile hf on hf.fproposerid = p.fid  " +
                            " left join T_HR_ATS_HolidayPolicySet hps on hf.fholidaypolicysetid = hps.fid     " +
                            " left join T_HR_ATS_HolidayPolicy hp on  hps.fid = hp.fholidaypolicysetid and thisL.FHOLIDAYPOLICYID = hp.fid  " +
                            " left join T_HR_ATS_HolidayType ht on ht.fid = hp.FHOLIDAYTYPEID and ht.FNUMBER = 'JQLX000001Y'     " +
                            " where hf.fattendfilestate = 1 and ht.FNUMBER = 'JQLX000001Y' and (lastL.cfcarryforward is null or lastL.cfcarryforward = 0) and thisL.FYEAR = " + year + " and lastL.fyear = " + (year - 1) + "";

                }
                if (StringUtils.isNotEmpty(personNumStr)) {
                    sql += " and p.fnumber in (" + personNumStr + ") ";
                }
                IRowSet rowSet = DbUtil.executeQuery(ctx, sql);
                while (rowSet.next()) {
                    HolidayLimitInfo lastYearHolidayLimitInfo = new HolidayLimitInfo();
                    lastYearHolidayLimitInfo.setId(BOSUuid.read(rowSet.getString("lastLfID")));
                    //今年结转额度
                    lastYearHolidayLimitInfo.setBigDecimal("Carryforward", rowSet.getBigDecimal("lastnextForward"));
                    // 去年 折算标准额度
                    BigDecimal lastYearConvertedLimit = rowSet.getBigDecimal("lcfconvertedlimit");
                    // 去年 初始化额度
                    BigDecimal lastYearInitializedLimit = rowSet.getBigDecimal("lCFInitializedLimit");
                    // 去年 从去年结转额度
                    BigDecimal lastYearLastCarryforward = rowSet.getBigDecimal("lCFLastCarryforward");
                    // 去年 标准额度 = 额度规则（折算额度）+初始化额度+从去年结转-结转到明年
                    //去年 折算标准额度 + 去年 初始化额度 + 去年 从去年结转额度
                    BigDecimal lastYearStandardLimit = lastYearConvertedLimit.add(lastYearInitializedLimit).add(lastYearLastCarryforward).subtract(lastYearHolidayLimitInfo.getBigDecimal("Carryforward"));

//					lastYearHolidayLimitInfo.setStandardLimit(lastYearStandardLimit);
//					lastYearHolidayLimitInfo.setRealLimit(lastYearHolidayLimitInfo.getStandardLimit().add(rowSet.getBigDecimal("LFADDORSUBLIMIT")));
//					lastYearHolidayLimitInfo.setRemainLimit(lastYearHolidayLimitInfo.getRealLimit().subtract(rowSet.getBigDecimal("LFUSEDLIMIT")).subtract(rowSet.getBigDecimal("lFreezeLimit")));
//					lastYearHolidayLimitInfo.setLastUpdateUser(ContextUtil.getCurrentUserInfo(ctx));
//					lastYearHolidayLimitInfo.setLastUpdateTime(new Timestamp(nowDate.getTime()));
                    lastYearList.add(lastYearHolidayLimitInfo);

                    HolidayLimitInfo thisYearHolidayLimitInfo = new HolidayLimitInfo();
                    thisYearHolidayLimitInfo.setId(BOSUuid.read(rowSet.getString("thisLFid")));
                    //上年转入额度
                    thisYearHolidayLimitInfo.setBigDecimal("LastCarryforward", rowSet.getBigDecimal("thislastforward"));
                    // 今年 折算标准额度
                    BigDecimal thisYearConvertedLimit = rowSet.getBigDecimal("tcfconvertedlimit");
                    // 今年 初始化额度
                    BigDecimal thisYearInitializedLimit = rowSet.getBigDecimal("tCFInitializedLimit");
                    // 今年 从去年结转额度 TODO xxx
                    BigDecimal thisYearCarryforward = rowSet.getBigDecimal("tCFCarryforward");
                    // 今年 标准额度 = 额度规则（折算额度）+初始化额度+从去年结转-结转到明年

                    // 标准额度 =折算标准额度 + 今年初始化额度 +  上年转入额度 - 去年结转额度  ;
                    BigDecimal thisYearStandardLimit = thisYearConvertedLimit.add(thisYearInitializedLimit).add(thisYearHolidayLimitInfo.getBigDecimal("LastCarryforward")).subtract(thisYearCarryforward);

                    thisYearHolidayLimitInfo.setStandardLimit(thisYearStandardLimit);
                    // 今年标准额度 + 增减额度   14 +0 =14
                    thisYearHolidayLimitInfo.setRealLimit(thisYearHolidayLimitInfo.getStandardLimit().add(rowSet.getBigDecimal("tFADDORSUBLIMIT")));
                    thisYearHolidayLimitInfo.setRemainLimit(thisYearHolidayLimitInfo.getRealLimit().subtract(rowSet.getBigDecimal("tFUSEDLIMIT")).subtract(rowSet.getBigDecimal("tFreezeLimit")));
                    thisYearHolidayLimitInfo.setLastUpdateUser(ContextUtil.getCurrentUserInfo(ctx));
                    thisYearHolidayLimitInfo.setLastUpdateTime(new Timestamp(nowDate.getTime()));
                    thisYearList.add(thisYearHolidayLimitInfo);
                }
            }
            if (lastYearList.size() > 0) {
                SelectorItemCollection sc = new SelectorItemCollection();
                sc.add(new SelectorItemInfo("Carryforward"));
                sc.add(new SelectorItemInfo("LastCarryforward"));
                HolidayLimitFactory.getLocalInstance(ctx).updatePartialBatchData(lastYearList, sc);
            }
            if (thisYearList.size() > 0) {
                SelectorItemCollection sc = new SelectorItemCollection();
                sc.add(new SelectorItemInfo("Carryforward"));
                sc.add(new SelectorItemInfo("LastCarryforward"));
                sc.add(new SelectorItemInfo("standardLimit"));
                sc.add(new SelectorItemInfo("realLimit"));
                sc.add(new SelectorItemInfo("remainLimit"));
                sc.add(new SelectorItemInfo("lastUpdateUser"));
                sc.add(new SelectorItemInfo("lastUpdateTime"));
                HolidayLimitFactory.getLocalInstance(ctx).updateBatchData(thisYearList);
            }

        } catch (ParseException e) {
            throw new BOSException(e);
        } catch (SQLException e) {
            throw new BOSException(e);
        }
    }

    /**
     * 护理假额度生成 JQLX000016Y
     */
    @Override
    protected void _creareNursingLeave(Context ctx, int year, String personNum) throws BOSException {
        try{
            Map<String,String> nextParam = Maps.newHashMap();
            nextParam.put("year",String.valueOf(year));
            nextParam.put("personNum",personNum);
            nextParam.put("mack","NursingLeave");
            OSFAppUtil.callService(ctx,"leaveAllowanceService",nextParam);
        } catch (EASBizException e) {
            throw new BOSException(e);
        }
        //createNursingOrParentalLeave(ctx, year, personNum, "JQLX000016Y", nursingLeaveLimit, "P");
    }

    /**
     * 育儿假额度生成 JQLX000015Y
     */
    @Override
    protected void _creareParentalLeave(Context ctx, int year, String personNum) throws BOSException {
        //createNursingOrParentalLeave(ctx, year, personNum, "JQLX000015Y", parentalLeaveLimit, "C");
        try{
            Map<String,String> nextParam = Maps.newHashMap();
            nextParam.put("year",String.valueOf(year));
            nextParam.put("personNum",personNum);
            nextParam.put("mack","ParentalLeave");
            OSFAppUtil.callService(ctx,"leaveAllowanceService",nextParam);
        } catch (EASBizException e) {
            throw new BOSException(e);
        }
    }

    private void createNursingOrParentalLeave(Context ctx, int year, String personNum, String policyNumber, int initialLimit, String cnLeave) throws BOSException {
        try {
            initialGlobalParam(ctx);
            String personFamilyTempTable = createPersonFamilyTempTable(ctx, cnLeave);
            // 当前时间
            Date nowDate = new Date();
            Date currentDate = new Date();
            if (year != 0) {
                currentDate = DateTimeUtils.parseDate(year + "-12-31");
            } else {
                year = DateTimeUtils.getYear(currentDate);
            }
            // 当前年份第一天
            String yearFirstDayStr = DateTimeUtils.getYear(currentDate) + "-01-01";
            Date yearFirstDay = DateTimeUtils.parseDate(yearFirstDayStr);
            // 当前年份最后一天
            String yearLastDayStr = DateTimeUtils.getYear(currentDate) + "-12-31";
            Date yearLastDay = DateTimeUtils.parseDate(yearLastDayStr);
            List<String> personNumberList = new ArrayList<String>();
            CoreBaseCollection addList = new CoreBaseCollection();
            CoreBaseCollection updateList = new CoreBaseCollection();
            String personNumStr = "";
            if (StringUtils.isNotEmpty(personNum)) {
                String[] personNumArr = personNum.split(",");
                for (int i = 0; i < personNumArr.length; i++) {
                    personNumberList.add("'" + personNumArr[i] + "'");
                }
                personNumStr = String.join(",", personNumberList);
            }
            // 置空相关的假期额度
            String clearQuotaSql = " update T_HR_ATS_HolidayLimit set FStandardLimit = 0, FRealLimit = FAddOrSubLimit,FRemainLimit = FAddOrSubLimit-FUsedLimit-FreezeLimit where fid in ( " +
                    " select l.fid from T_HR_ATS_HolidayLimit l " +
                    " left join T_HR_ATS_HolidayPolicy hp on  hp.fid = l.FHOLIDAYPOLICYID " +
                    " left join T_HR_ATS_HolidayType ht on hp.FHOLIDAYTYPEID = ht.fid " +
                    " left join t_bd_person p on p.fid = l.FPROPOSERID " +
                    " where ht.FNUMBER = '" + policyNumber + "' and l.FYEAR = " + year + " and l.FCYCLEBEGINDATE >= p.fhiredate and l.FCYCLEBEGINDATE <= p.FLEFFDT ";
            if (StringUtils.isNotEmpty(personNumStr)) {
                clearQuotaSql += " and p.fnumber in (" + personNumStr + ")) ";
            } else {
                clearQuotaSql += " ) ";
            }
            DbUtil.execute(ctx, clearQuotaSql);
            // 清理空数据
            String deleteZeroQuotaSql = "delete from T_HR_ATS_HolidayLimit where FHOLIDAYPOLICYID in (select hp.fid from T_HR_ATS_HolidayPolicy hp " +
                    "left join T_HR_ATS_HolidayType ht on hp.FHOLIDAYTYPEID = ht.fid where  ht.FNUMBER = '" + policyNumber + "') and FYEAR = " + year + " and FStandardLimit = 0 and FRealLimit = 0 and FAddOrSubLimit = 0 and FRemainLimit = 0 and FUsedLimit = 0 and FreezeLimit = 0 ";
            if (StringUtils.isNotEmpty(personNumStr)) {
                deleteZeroQuotaSql += " and FProposerID in (select fid from t_bd_person where fnumber in (" + personNumStr + ") ) ";
            }
            DbUtil.execute(ctx, deleteZeroQuotaSql);
            String sql = "/*dialect*/select f.FPERSONID,p.fnumber, case when to_char(f.CFStartTime,'yyyy') < " + year + " then to_date('" + year + "-01-01','yyyy-MM-dd') else f.CFStartTime end CFStartTime," +
                    " case when f.CFEndTime is null or to_char(f.CFEndTime,'yyyy') > " + year + " then to_date('" + year + "-12-31','yyyy-MM-dd') else f.CFEndTime end CFEndTime ," +
                    " case when rbe.fid is null then null else rbe.FBIZDATE end leaveDate,p.fhiredate,hf.FADMINORGUNITID, hf.FHRORGUNITID ,hf.FPOSITIONID, l.fid limitId,ebe.FPROBATION," +
                    " ebe.FPLANFORMALDATE,hp.fid holidayPolicyId,l.FADDORSUBLIMIT,l.FUSEDLIMIT,l.FREEZELIMIT,l.FCYCLEBEGINDATE,l.FCYCLEENDDATE from " + personFamilyTempTable + " f " +
                    " left join t_bd_person p on p.fid = f.FPERSONID " +
                    " left join T_HR_ATS_AtsHolidayFile hf on hf.fproposerid = f.FPERSONID " +
                    " left join T_HR_ATS_HolidayPolicySet hps on hf.fholidaypolicysetid = hps.fid  " +
                    " left join T_HR_ATS_HolidayPolicy hp on hps.fid = hp.fholidaypolicysetid" +
                    " left join T_HR_ATS_HolidayType ht on ht.FNUMBER = '" + policyNumber + "' and ht.fid = hp.FHOLIDAYTYPEID  " +

                    " left join T_HR_ATS_HolidayLimit l on hp.fid = l.FHOLIDAYPOLICYID and l.FPROPOSERID = f.FPERSONID and l.FYEAR = " + year + " and f.CFStartTime<=l.FCYCLEBEGINDATE and f.CFEndTime>=l.FCYCLEBEGINDATE  and l.FCYCLEBEGINDATE >= p.fhiredate and l.FCYCLEENDDATE >= p.fhiredate " +
//					" left join T_HR_EmpEnrollBizBillEntry ebe on ebe.FPERSONID = f.FPERSONID and ebe.FBIZDATE = p.fhiredate " +
//					" left join T_HR_EmpEnrollBizBill eb on ebe.FBILLID = eb.FID and eb.FBILLSTATE = 3 " +
//					" left join T_HR_ResignBizBillEntry rbe on rbe.FPERSONID = f.FPERSONID and (p.fhiredate<=rbe.FBIZDATE or rbe.FBIZDATE is null)" +
//					" left join T_HR_ResignBizBill rb on rb.fid = rbe.FBILLID and rb.FBILLSTATE = 3  " +

                    " left join ( " +
                    " select rownum rownumber,ebe.FPERSONID, " +
                    " ebe.FPROBATION,ebe.FPLANFORMALDATE, ebe.FBIZDATE " +
                    " from T_HR_EmpEnrollBizBillEntry ebe " +
                    " inner join (select re1.fpersonid,max(re1.fbizdate) fbizdate,count(fid) from T_HR_EmpEnrollBizBillEntry re1 " +
                    " group by re1.fpersonid) re1 on ebe.fpersonid=re1.fpersonid and re1.fbizdate=ebe.fbizdate " +
                    " left join T_HR_EmpEnrollBizBill eb on ebe.FBILLID = eb.FID " +
                    " and eb.FBILLSTATE = 3 " +
                    " order by ebe.fbizdate desc) ebe " +
                    " on  ebe.FPERSONID = p.fid " +
                    " and ebe.FBIZDATE = p.fhiredate " +
                    " left join( " +
                    " select rownum rownumber,rbe.fid, rbe.FPERSONID, " +
                    " rbe.FENTERDATE, rbe.CFWcategoryID, rbe.FBIZDATE " +
                    " from T_HR_ResignBizBillEntry rbe " +
                    " inner join (select re1.fpersonid,max(re1.fbizdate) fbizdate,count(fid) from T_HR_ResignBizBillEntry re1 " +
                    " group by re1.fpersonid) re1 on rbe.fpersonid=re1.fpersonid and re1.fbizdate=rbe.fbizdate " +
                    " left join T_HR_ResignBizBill rb on rb.fid = rbe.FBILLID " +
                    " and rb.FBILLSTATE = 3 order by rbe.fbizdate desc " +
                    " ) rbe on  rbe.FPERSONID = p.fid " +
                    " and p.fhiredate = rbe.FENTERDATE " +

                    " where ht.FNUMBER = '" + policyNumber + "' and hf.fattendfilestate = 1 and f.CFStartTime <= to_date('" + yearLastDayStr + "','yyyy-MM-dd') and (f.CFEndTime >= to_date('" + yearFirstDayStr + "','yyyy-MM-dd') or f.CFEndTime is null)  and  to_char(p.fhiredate,'yyyy')<=" + year + " and to_char(p.FLEFFDT,'yyyy')>=" + year;

            if (StringUtils.isNotEmpty(personNumStr)) {
                sql += " and p.fnumber in (" + personNumStr + ") ";
            }

            IRowSet iRowSet = DbUtil.executeQuery(ctx, sql);
            while (iRowSet.next()) {
                String holidayPolicyId = iRowSet.getString("holidayPolicyId");
                if (StringUtils.isEmpty(holidayPolicyId)) {
                    continue;
                }
                BigDecimal standardLimit = BigDecimal.valueOf(initialLimit);
                String limitId = iRowSet.getString("limitId");
                // 入职日期
                java.sql.Date joinDate = iRowSet.getDate("fhiredate");
                java.sql.Date fplanformaldate = iRowSet.getDate("FPLANFORMALDATE");
                // 离职日期
                java.sql.Date leaveDate = iRowSet.getDate("leaveDate");
                // 开始日期
                java.sql.Date cfStartTime = iRowSet.getDate("CFStartTime");
                // 生效日期
                java.sql.Date effectDate = iRowSet.getDate("CFStartTime");
                // 结束日期
                java.sql.Date cfEndTime = iRowSet.getDate("CFEndTime");
                // 入职折算
                if (DateTimeUtils.getYear(joinDate) == DateTimeUtils.getYear(cfStartTime) && joinDate.getTime() > cfStartTime.getTime()) {
                    cfStartTime = joinDate;
                    effectDate = iRowSet.getDate("FPLANFORMALDATE") != null ? iRowSet.getDate("FPLANFORMALDATE") : joinDate;
                } else if (fplanformaldate != null && DateTimeUtils.getYear(fplanformaldate) == DateTimeUtils.getYear(cfStartTime) && fplanformaldate.getTime() > cfStartTime.getTime()) {
                    effectDate = fplanformaldate;
                }
                // 离职折算
                if (leaveDate != null && DateTimeUtils.getYear(currentDate) == DateTimeUtils.getYear(leaveDate)) {
                    if (DateTimeUtils.getYear(leaveDate) == DateTimeUtils.getYear(cfEndTime) && cfEndTime.getTime() > leaveDate.getTime()) {
                        cfEndTime = leaveDate;
                    }
                }
                // 开始时间必须小于或等于结束日期
                if (cfStartTime.getTime() > cfEndTime.getTime()) {
                    continue;
                }
                standardLimit = standardLimit.multiply(BigDecimal.valueOf(DateTimeUtils.getMonth(cfEndTime) - DateTimeUtils.getMonth(cfStartTime) + 1)).divide(BigDecimal.valueOf(MONTH_NUM_12), 10, BigDecimal.ROUND_HALF_UP);
                // 年假取整
                // 整数部分
                BigDecimal standardLimitInteger = standardLimit.setScale(0, RoundingMode.FLOOR);
                // 小数部分
                BigDecimal standardLimitDecimal = standardLimit.subtract(standardLimitInteger);
                if (Double.doubleToLongBits(INTEGERPERCISION_HALF) == Double.doubleToLongBits(nursingAndParentalLeaveIntegerPrecision)) {
                    if (StringUtils.equals(INTEGERMETHOD_UP, nursingAndParentalLeaveIntegerMethod)) {
                        if (standardLimitDecimal.compareTo(BigDecimal.valueOf(0.5)) > 0) {
                            standardLimit = standardLimit.setScale(0, RoundingMode.CEILING);
                        } else if (standardLimitDecimal.compareTo(BigDecimal.ZERO) > 0) {
                            standardLimit = standardLimitInteger.add(BigDecimal.valueOf(0.5));
                        } else {
                            standardLimit = standardLimitInteger;
                        }
                    } else {
                        if (standardLimitDecimal.compareTo(BigDecimal.valueOf(0.5)) > 0) {
                            standardLimit = standardLimitInteger.add(BigDecimal.valueOf(0.5));
                        } else {
                            standardLimit = standardLimit.setScale(0, RoundingMode.FLOOR);
                        }
                    }
                } else {
                    if (StringUtils.equals(INTEGERMETHOD_UP, nursingAndParentalLeaveIntegerMethod)) {
                        standardLimit = standardLimit.setScale(0, RoundingMode.CEILING);
                    } else {
                        standardLimit = standardLimit.setScale(0, RoundingMode.FLOOR);
                    }
                }

                if (StringUtils.isNotEmpty(limitId)) {
                    HolidayLimitInfo holidayLimitInfo = new HolidayLimitInfo();
                    holidayLimitInfo.setId(BOSUuid.read(limitId));
                    // 标准额度
                    holidayLimitInfo.setStandardLimit(standardLimit);
                    holidayLimitInfo.setRealLimit(standardLimit.add(iRowSet.getBigDecimal("FADDORSUBLIMIT")));
                    holidayLimitInfo.setRemainLimit(standardLimit.add(iRowSet.getBigDecimal("FADDORSUBLIMIT")).subtract(iRowSet.getBigDecimal("FUSEDLIMIT")).subtract(iRowSet.getBigDecimal("FreezeLimit")));
                    holidayLimitInfo.setCycleBeginDate(cfStartTime);
                    holidayLimitInfo.setCycleEndDate(cfEndTime);
                    holidayLimitInfo.setEffectDate(effectDate);
                    holidayLimitInfo.setDelayDate(yearLastDay);
                    if (leaveDate != null && leaveDate.getTime() == cfEndTime.getTime()) {
                        holidayLimitInfo.setDelayDate(cfEndTime);
                    }
                    if (StringUtils.isNotEmpty(iRowSet.getString("FADMINORGUNITID"))) {
                        AdminOrgUnitInfo adminOrgUnitInfo = new AdminOrgUnitInfo();
                        adminOrgUnitInfo.setId(BOSUuid.read(iRowSet.getString("FADMINORGUNITID")));
                        holidayLimitInfo.setAdminOrgUnit(adminOrgUnitInfo);
                    }

                    if (StringUtils.isNotEmpty(iRowSet.getString("FHRORGUNITID"))) {
                        HROrgUnitInfo hrOrgUnitInfo = new HROrgUnitInfo();
                        hrOrgUnitInfo.setId(BOSUuid.read(iRowSet.getString("FHRORGUNITID")));
                        holidayLimitInfo.setHrOrgUnit(hrOrgUnitInfo);
                    }
                    if (StringUtils.isNotEmpty(iRowSet.getString("FPOSITIONID"))) {
                        PositionInfo positionInfo = new PositionInfo();
                        positionInfo.setId(BOSUuid.read(iRowSet.getString("FPOSITIONID")));
                        holidayLimitInfo.setPosition(positionInfo);
                    }
                    holidayLimitInfo.setLastUpdateUser(ContextUtil.getCurrentUserInfo(ctx));
                    holidayLimitInfo.setLastUpdateTime(new Timestamp(nowDate.getTime()));
                    updateList.add(holidayLimitInfo);
                } else {
                    HolidayLimitInfo holidayLimitInfo = new HolidayLimitInfo();
                    holidayLimitInfo.setStandardLimit(standardLimit);
                    holidayLimitInfo.setRealLimit(standardLimit);
                    holidayLimitInfo.setRemainLimit(standardLimit);
                    holidayLimitInfo.setFreezeLimit(BigDecimal.ZERO);
                    holidayLimitInfo.setUsedLimit(BigDecimal.ZERO);
                    holidayLimitInfo.setAddOrSubLimit(BigDecimal.ZERO);
                    holidayLimitInfo.setPreOverdraftLimit(BigDecimal.ZERO);
                    holidayLimitInfo.setCycleBeginDate(cfStartTime);
                    holidayLimitInfo.setCycleEndDate(cfEndTime);
                    holidayLimitInfo.setEffectDate(effectDate);
                    holidayLimitInfo.setDelayDate(yearLastDay);
                    if (leaveDate != null && leaveDate.getTime() == cfEndTime.getTime()) {
                        holidayLimitInfo.setDelayDate(cfEndTime);
                    }
                    holidayLimitInfo.setYear(DateTimeUtils.getYear(yearFirstDay));
                    HolidayPolicyInfo holidayPolicyInfo = new HolidayPolicyInfo();
                    holidayPolicyInfo.setId(BOSUuid.read(holidayPolicyId));
                    holidayLimitInfo.setHolidayPolicy(holidayPolicyInfo);
                    holidayLimitInfo.setHolidayUnit(HolidayTypeUnitEnum.day);
                    holidayLimitInfo.setEnableCycle(true);
                    PersonInfo personInfo = new PersonInfo();
                    personInfo.setId(BOSUuid.read(iRowSet.getString("FPERSONID")));
                    holidayLimitInfo.setProposer(personInfo);
                    holidayLimitInfo.setStatus(HolidayLimitStatus.audited);
                    if (StringUtils.isNotEmpty(iRowSet.getString("FADMINORGUNITID"))) {
                        AdminOrgUnitInfo adminOrgUnitInfo = new AdminOrgUnitInfo();
                        adminOrgUnitInfo.setId(BOSUuid.read(iRowSet.getString("FADMINORGUNITID")));
                        holidayLimitInfo.setAdminOrgUnit(adminOrgUnitInfo);
                    }

                    if (StringUtils.isNotEmpty(iRowSet.getString("FHRORGUNITID"))) {
                        HROrgUnitInfo hrOrgUnitInfo = new HROrgUnitInfo();
                        hrOrgUnitInfo.setId(BOSUuid.read(iRowSet.getString("FHRORGUNITID")));
                        holidayLimitInfo.setHrOrgUnit(hrOrgUnitInfo);
                    }
                    if (StringUtils.isNotEmpty(iRowSet.getString("FPOSITIONID"))) {
                        PositionInfo positionInfo = new PositionInfo();
                        positionInfo.setId(BOSUuid.read(iRowSet.getString("FPOSITIONID")));
                        holidayLimitInfo.setPosition(positionInfo);
                    }

                    CtrlUnitInfo ctrlUnitInfo = new CtrlUnitInfo();
                    ctrlUnitInfo.setId(BOSUuid.read("00000000-0000-0000-0000-000000000000CCE7AED4"));
                    holidayLimitInfo.setCU(ctrlUnitInfo);
                    holidayLimitInfo.setCycleDate(yearLastDay);
                    holidayLimitInfo.setCreator(ContextUtil.getCurrentUserInfo(ctx));
                    holidayLimitInfo.setCreateTime(new Timestamp(nowDate.getTime()));
                    holidayLimitInfo.setLastUpdateUser(ContextUtil.getCurrentUserInfo(ctx));
                    holidayLimitInfo.setLastUpdateTime(new Timestamp(nowDate.getTime()));
                    addList.add(holidayLimitInfo);
                }
            }
            if (addList.size() > 0) {
                HolidayLimitFactory.getLocalInstance(ctx).addnewBatchData(addList);
            }
            if (updateList.size() > 0) {
                HolidayLimitFactory.getLocalInstance(ctx).updateBatchData(updateList);
            }
        } catch (ParseException | SQLException e) {
            throw new BOSException(e);
        } catch (EASBizException e) {
            throw new BOSException(e);
        }
    }

    /**
     * 创建社会关系临时表 处理日期区间合并数据
     *
     * @param ctx
     * @param cnLeave
     * @return
     * @throws BOSException
     */
    private String createPersonFamilyTempTable(Context ctx, String cnLeave) throws BOSException {
        String dbType = ContextUtil.getDbType(ctx);
        String view_pf_PersonFamilyTempTable = "";
        // 育儿护理多段统计是否更新视图脚本
        if (StringUtils.equalsIgnoreCase(nursingAndParentalLeaveUpdateSql, "Y")) {
            // 删除视图
            if (StringUtils.equalsIgnoreCase("MS SQL Server", dbType)) {
                String dropView = " IF EXISTS (SELECT * FROM sys.views WHERE name = 'view_pf_DateRanges_" + cnLeave + "') " +
                        " DROP VIEW view_pf_DateRanges_" + cnLeave;
                DbUtil.execute(ctx, dropView);
                dropView = " IF EXISTS (SELECT * FROM sys.views WHERE name = 'view_pf_CTE_" + cnLeave + "') " +
                        " DROP VIEW view_pf_CTE_" + cnLeave;
                DbUtil.execute(ctx, dropView);
                dropView = " IF EXISTS (SELECT * FROM sys.views WHERE name = 'view_pf_MergedRanges_" + cnLeave + "') " +
                        "   DROP VIEW view_pf_MergedRanges_" + cnLeave;
                DbUtil.execute(ctx, dropView);
                dropView = " IF EXISTS (SELECT * FROM sys.views WHERE name = 'view_pf_GroupedRanges_" + cnLeave + "') " +
                        "   DROP VIEW view_pf_GroupedRanges_" + cnLeave;
                DbUtil.execute(ctx, dropView);
            }

            // 创建视图
            String createView = " /*dialect*/create or replace view view_pf_DateRanges_" + cnLeave + " as ( " +
                    " select CFStartTime StartDate,CFEndTime EndDate,FPERSONID PersonID from t_hr_personfamily where CFCnleave = '" + cnLeave + "'  " +
                    " ) ";
            if (StringUtils.equalsIgnoreCase("MS SQL Server", dbType)) {
                createView = " /*dialect*/create view view_pf_DateRanges_" + cnLeave + " as ( " +
                        " select CFStartTime StartDate,CFEndTime EndDate,FPERSONID PersonID from t_hr_personfamily where CFCnleave = '" + cnLeave + "'  " +
                        " ) ";
            }
            DbUtil.execute(ctx, createView);

            createView = " /*dialect*/create or replace view view_pf_CTE_" + cnLeave + " AS ( " +
                    "   SELECT PersonID,StartDate, EndDate,LAG(EndDate) OVER (PARTITION BY PersonID ORDER BY StartDate) AS prev_end_date FROM view_pf_DateRanges_" + cnLeave +
                    ") ";
            if (StringUtils.equalsIgnoreCase("MS SQL Server", dbType)) {
                createView = " /*dialect*/create view view_pf_CTE_" + cnLeave + " AS ( " +
                        "   SELECT PersonID,StartDate, EndDate,LAG(EndDate) OVER (PARTITION BY PersonID ORDER BY StartDate) AS prev_end_date FROM view_pf_DateRanges_" + cnLeave +
                        ") ";
            }
            DbUtil.execute(ctx, createView);

            createView = " /*dialect*/create or replace view view_pf_MergedRanges_" + cnLeave + " AS ( " +
                    "    SELECT PersonID,StartDate,EndDate,CASE WHEN StartDate <= prev_end_date + INTERVAL '1 day'  THEN 0 ELSE 1 END AS is_overlap FROM view_pf_CTE_" + cnLeave +
                    ") ";
            if (StringUtils.equalsIgnoreCase("MS SQL Server", dbType)) {
                createView = " /*dialect*/create view view_pf_MergedRanges_" + cnLeave + " AS ( " +
                        "    SELECT PersonID,StartDate,EndDate,CASE WHEN StartDate <= DATEADD(day, 1, prev_end_date) THEN 0 ELSE 1 END AS is_overlap FROM view_pf_CTE_" + cnLeave +
                        ") ";
            }
            DbUtil.execute(ctx, createView);

            createView = " /*dialect*/create or replace view view_pf_GroupedRanges_" + cnLeave + " AS ( " +
                    "    SELECT PersonID,StartDate,EndDate,SUM(is_overlap) OVER (PARTITION BY PersonID ORDER BY StartDate) AS grp FROM view_pf_MergedRanges_" + cnLeave +
                    ") ";
            if (StringUtils.equalsIgnoreCase("MS SQL Server", dbType)) {
                createView = " /*dialect*/create view view_pf_GroupedRanges_" + cnLeave + " AS ( " +
                        "    SELECT PersonID,StartDate,EndDate,SUM(is_overlap) OVER (PARTITION BY PersonID ORDER BY StartDate) AS grp FROM view_pf_MergedRanges_" + cnLeave +
                        ") ";
            }
            DbUtil.execute(ctx, createView);
        }

        view_pf_PersonFamilyTempTable = " (SELECT PersonID fpersonid,MIN(StartDate) AS CFStartTime,MAX(EndDate) AS CFEndTime FROM view_pf_GroupedRanges_" + cnLeave + " GROUP BY PersonID, grp ORDER BY PersonID, CFStartTime) ";
        if (StringUtils.equalsIgnoreCase("MS SQL Server", dbType)) {
            view_pf_PersonFamilyTempTable = " (SELECT top 100 percent PersonID fpersonid,MIN(StartDate) AS CFStartTime,MAX(EndDate) AS CFEndTime FROM view_pf_GroupedRanges_" + cnLeave + " GROUP BY PersonID, grp ORDER BY PersonID, CFStartTime) ";
        }
        return view_pf_PersonFamilyTempTable;
    }

    /**
     * 员工列表
     *
     * @param ctx
     * @param
     * @return
     * @throws BOSException
     * @throws SQLException
     */
    private List<String> getPersonData(Context ctx, String leaveNumber, int year) throws BOSException, SQLException {
        String nursingSql = " SELECT a.FPROPOSERID FROM T_HR_ATS_HolidayLimit as a ,T_HR_ATS_HolidayPolicy as b , T_HR_ATS_HolidayType c " +
                " where a.FHOLIDAYPOLICYID  = b.FID  and b.FHOLIDAYTYPEID = c.FID  and c.FNUMBER  = '" + leaveNumber + "' and FYear =  " + year + " ";
        IRowSet rs = DbUtil.executeQuery(ctx, nursingSql);
        List<String> personList = new ArrayList<String>();
        while (rs.next()) {
            personList.add(rs.getString("FPROPOSERID"));
        }
        return personList;
    }

    /**
     * 开始时间
     *
     * @param
     * @return
     */
    private static Date getStartDate(Date startDate) {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 0);
        if (startDate.before(calendar.getTime())) {
            startDate = calendar.getTime();
        }
        return startDate;
    }

    /**
     * 结束时间
     *
     * @param
     * @return
     */
    private static Date getEndDate(Date endDate) {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        calendar.set(Calendar.YEAR, year);
        calendar.roll(Calendar.DAY_OF_YEAR, -1);
        calendar.set(Calendar.MONTH, 11);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        if (endDate.after(calendar.getTime())) {
            endDate = calendar.getTime();
        }
        return endDate;
    }


    /**
     * 返回休假天数
     *
     * @param day
     * @param month
     * @return
     */
    public double getLeaveDay(double day, int month) {
        double leaveDay = day / 12.0 * month;
        int floorInt = (int) leaveDay;
        double decimals = leaveDay - floorInt;
        if (decimals < 0.5) {
            System.out.print("可休假额度：" + floorInt);
            return floorInt;
        } else {
            System.out.print("可休假额度：" + floorInt + 0.5);
            return (floorInt + 0.5);
        }

    }

    /**
     * 获取假期类型为对应的假期制度id集合
     *
     * @param ctx
     * @param holidayNumber
     * @return
     */
    public String getHolidayPolicyIds(Context ctx, String holidayNumber) {
        StringBuffer holidayPolicyIds = new StringBuffer();
        try {
            HolidayTypeCollection holidayTypeCollection = HolidayTypeFactory.getLocalInstance(ctx).getHolidayTypeCollection("where number = '" + holidayNumber + "'");
            if (holidayTypeCollection != null && holidayTypeCollection.size() > 0) {
                HolidayPolicyCollection holidayPolicyCollection = HolidayPolicyFactory.getLocalInstance(ctx).getHolidayPolicyCollection("where holidayType = '" + holidayTypeCollection.get(0).getId().toString() + "'");
                for (int i = 0; i < holidayPolicyCollection.size(); i++) {
                    holidayPolicyIds.append("'" + holidayPolicyCollection.get(i).getId().toString() + "',");
                }
                if (holidayPolicyIds.length() > 0) {
                    holidayPolicyIds = holidayPolicyIds.deleteCharAt(holidayPolicyIds.length() - 1);
                }
            }
        } catch (BOSException e) {
            e.printStackTrace();
        }
        return holidayPolicyIds.toString();
    }

    /**
     * 根据假期额度名称获取id
     * @param ctx
     * @param holidayName
     * @return
     */
//	public String getHolidayPolicyID(Context ctx, String holidayNumber) {
//		try {
//			HolidayTypeCollection holidayTypeCollection = HolidayTypeFactory.getLocalInstance(ctx).getHolidayTypeCollection("where number = '"+holidayNumber+"'");
//			if(holidayTypeCollection!=null && holidayTypeCollection.size()>0) {
//				HolidayPolicyCollection holidayPolicyCollection = HolidayPolicyFactory.getLocalInstance(ctx).getHolidayPolicyCollection("where holidayType = '"+holidayTypeCollection.get(0).getId().toString()+"'");
//				if(holidayPolicyCollection != null && holidayPolicyCollection.size()>0) {
//					return holidayPolicyCollection.get(0).getId().toString();
//				}
//			}
//		} catch (BOSException e) {
//			e.printStackTrace();
//		}
//		return "";
//	}
}