package com.kingdee.eas.custom.compensation.service;

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.eas.util.app.DbUtil;
import com.kingdee.jdbc.rowset.IRowSet;
import com.kingdee.shr.compensation.service.CalSubmitSchemeFunctionService;

import com.kingdee.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.sql.Date;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;


/**
 * 薪酬方案计算函数服务扩展类。
 * <p>
 * 提供以下薪酬计算相关的扩展函数：
 * <ul>
 *   <li>当月入职/离职/转正人数统计</li>
 *   <li>月末净增人数（入职-离职）</li>
 *   <li>获取适用薪酬方案名称</li>
 *   <li>获取薪酬档案中的固定薪资项目值</li>
 * </ul>
 */
public class CalSubmitSchemeFunctionServiceEx extends CalSubmitSchemeFunctionService {
    private static final Logger logger = LoggerFactory.getLogger(CalSubmitSchemeFunctionServiceEx.class);


    /**
     * 人才留存奖金
     * @param ctx
     * @param paramMap
     * @param tempMap
     * @param mainTableName
     * @param mainTableRowFilter
     * @return
     */
    public double getTalentRetentionBonus(Context ctx, Map<String, Object> paramMap, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter,double isFixed) {
        try {
            //todo
            //计算的员工id
            String personId = (String) paramMap.get(mainTableName.toUpperCase() + "_FPERSONID");
            //计算的数据行
            String id = (String) paramMap.get(mainTableName.toUpperCase() + "_FID");
            String Effect = getEffect(ctx, tempMap, mainTableName, mainTableRowFilter, id);

            StringBuilder sql = new StringBuilder();
            sql.append(" /*dialect*/ ");
            // 主查询：按核算表和生效月份分组统计入职人数
            sql.append(" SELECT mt.fpersonid,substring(convert(varchar,mt.FEffectDate,120),0,8) FEffectDate,count(abt.pid) pNum from ").append(mainTableName).append(" mt ");
            // 关联子查询：通过北森应聘表匹配到人员，再关联其最近一次入职记录
            sql.append(" left join ( select ab.CFRecruitOwnerID,p.fid pid,t.fbizDate bizDate ");
            sql.append(" from CT_REC_ApplicantBeisen ab ");
            sql.append(" inner join T_REC_ResumeBaseRec rb on rb.CFCANDIDATEID = ab.CFCANDIDATEID ");
            sql.append(" inner join t_bd_person p on isnull(p.FIDCARDNO,p.FPASSPORTNO)=isnull(rb.FIdentityCardNo,rb.FPassportNo) ");
            // 取每个人员最近一次入职记录（ROW_NUMBER + rn=1）
            sql.append(" left join ( ");
            sql.append("         SELECT FPERSONID, FBIZDATE ");
            sql.append(" FROM ( ");
            sql.append("         SELECT ");
            sql.append("         e.FPERSONID, ");
            sql.append("         e.FBIZDATE, ");
            sql.append("         ROW_NUMBER() OVER (PARTITION BY e.FPERSONID ORDER BY e.FBIZDATE DESC) AS rn ");
            sql.append("         FROM T_HR_EmpEnrollBizBillEntry e ");
            sql.append("         LEFT JOIN T_HR_EmpEnrollBizBill b ON b.fid = e.FBillID ");
            sql.append("         where b.FBillState=3 ");
            sql.append("  ) t ");
            sql.append(" WHERE rn = 1) t on t.fpersonid=p.fid ) abt on abt.CFRecruitOwnerID=mt.fpersonid ");
            // 入职日期在生效日期当月范围内：[当月第一天, 下月第一天)
            sql.append(" AND abt.bizDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, mt.FEffectDate), 0)");              // 当月第一天 00:00:00.000
            sql.append(" AND abt.bizDate < DATEADD(MONTH, DATEDIFF(MONTH, 0, mt.FEffectDate) + 1, 0) ");           // 下个月第一天 00:00:00.000
            sql.append(" AND mt.fid in(").append(mainTableRowFilter).append(") group by mt.fpersonid,substring(convert(varchar,mt.FEffectDate,120),0,8) ");
            IRowSet rs = DbUtil.executeQuery(ctx, sql.toString());
            //fixPayMap = new HashMap<>();
            while (rs.next()) {
                //获取人数
                String fpersonid = rs.getString("fpersonid");
                String FEffectDate = rs.getString("FEffectDate");
                int pNum = rs.getInt("pNum");
                //fixPayMap.put(fpersonid + "_" + FEffectDate, pNum);
            }
        }catch (Exception e){
            logger.error(e.getMessage(),e);
        }
        return 0D;
    }


    /**
     * 当月净增人数 = 当月入职人数 - 当月离职人数（通过招聘渠道入职但当月即离职的人员统计）。
     * @param ctx                上下文
     * @param paramMap           参数（含 FPERSONID、FID）
     * @param tempMap            临时缓存 Map
     * @param mainTableName      计算表对象名
     * @param mainTableRowFilter 计算表数据行过滤条件
     * @return 当月净增人数
     */
    public double getEndMonthRetainedUsers(Context ctx, Map<String, Object> paramMap, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter) {
        try {
            //计算的员工id
            String personId = (String) paramMap.get(mainTableName.toUpperCase() + "_FPERSONID");
            //计算的数据行
            String id = (String) paramMap.get(mainTableName.toUpperCase() + "_FID");
            String Effect = getEffect(ctx, tempMap, mainTableName,mainTableRowFilter, id);
            // 获取当月入职人数
            double ruzhiNum = getMonthRuzhiUsers(ctx, paramMap, tempMap, mainTableName, mainTableRowFilter);
            // 获取当月离职人数
            double lizhiNum = getMonthLiZhiUsers(ctx, paramMap, tempMap, mainTableName, mainTableRowFilter);
            // 净增 = 入职 - 离职
            return ((double) ruzhiNum - lizhiNum);
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            //ex.printStackTrace();
        }
        return (double) 0.0F;
    }
    /**
     * 当月入职人数（通过招聘渠道入职且在生效日期当月入职的人数）。
     * @param ctx                上下文
     * @param paramMap           参数（含 FPERSONID、FID）
     * @param tempMap            临时缓存 Map
     * @param mainTableName      计算表对象名
     * @param mainTableRowFilter 计算表数据行过滤条件
     * @return 当前人员在生效日期对应的当月入职人数
     */
    public double getMonthRuzhiUsers(Context ctx, Map<String, Object> paramMap, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter) {
        try {
            //计算的员工id
            String personId = (String) paramMap.get(mainTableName.toUpperCase() + "_FPERSONID");
            //计算的数据行
            String id = (String) paramMap.get(mainTableName.toUpperCase() + "_FID");
            String Effect = getEffect(ctx, tempMap, mainTableName,mainTableRowFilter, id);
            // 入职人数缓存 key
            String ruZhiMapKey = "getMonthRuzhiUsers_Map";
            // 查询生效日期当月入职的人数
            getRuZhiPersonNum(ctx, tempMap, mainTableName, mainTableRowFilter, ruZhiMapKey);


            Map<String, Integer> fixPayMap = (Map) tempMap.get(ruZhiMapKey);

            String key = personId + "_" + Effect;
            if (fixPayMap.containsKey(key)) {
                int num = fixPayMap.containsKey(key) ? fixPayMap.get(key) : 0;
                return (double) (num);
            } else {
                return (double) 0.0F;
            }

        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            //ex.printStackTrace();
        }
        return (double) 0.0F;
    }
    /**
     * 当月转正人数（通过招聘渠道入职且在生效日期当月转正的人数）。
     * @param ctx                上下文
     * @param paramMap           参数（含 FPERSONID、FID）
     * @param tempMap            临时缓存 Map
     * @param mainTableName      计算表对象名
     * @param mainTableRowFilter 计算表数据行过滤条件
     * @return 当前人员在生效日期对应的当月转正人数
     */
    public double getMonthZhuanZhengUsers(Context ctx, Map<String, Object> paramMap, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter) {
        try {
            //计算的员工id
            String personId = (String) paramMap.get(mainTableName.toUpperCase() + "_FPERSONID");
            //计算的数据行
            String id = (String) paramMap.get(mainTableName.toUpperCase() + "_FID");
            String Effect = getEffect(ctx, tempMap, mainTableName,mainTableRowFilter, id);
            // 转正人数缓存 key
            String zhuanZhengMapKey = "getMonthZhuanZhengUsers_Map";
            // 查询生效日期当月转正的人数
            getZhuanZhengPersonNum(ctx, tempMap, mainTableName, mainTableRowFilter, zhuanZhengMapKey);
            Map<String, Integer> fixPayMap = (Map) tempMap.get(zhuanZhengMapKey);
            String key = personId + "_" + Effect;
            if (fixPayMap.containsKey(key)) {
                int num = fixPayMap.containsKey(key) ? fixPayMap.get(key) : 0;
                return (double) (num);
            } else {
                return (double) 0.0F;
            }

        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            //ex.printStackTrace();
        }
        return (double) 0.0F;
    }

    /**
     * 当月离职人数（通过招聘渠道入职且在生效日期当月离职的人数）。
     * @param ctx                上下文
     * @param paramMap           参数（含 FPERSONID、FID）
     * @param tempMap            临时缓存 Map
     * @param mainTableName      计算表对象名
     * @param mainTableRowFilter 计算表数据行过滤条件
     * @return 当前人员在生效日期对应的当月离职人数
     */
    public double getMonthLiZhiUsers(Context ctx, Map<String, Object> paramMap, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter) {
        try {
            //计算的员工id
            String personId = (String) paramMap.get(mainTableName.toUpperCase() + "_FPERSONID");
            //计算的数据行
            String id = (String) paramMap.get(mainTableName.toUpperCase() + "_FID");
            String Effect = getEffect(ctx, tempMap, mainTableName,mainTableRowFilter, id);
            // 离职人数缓存 key
            String liZhiMapKey = "getMonthLiZhiUsers_Map";
            // 查询生效日期当月离职的人数
            getLiZhiPersonNum(ctx, tempMap, mainTableName, mainTableRowFilter, liZhiMapKey);
            Map<String, Integer> fixPayMap = (Map) tempMap.get(liZhiMapKey);
            String key = personId + "_" + Effect;
            if (fixPayMap.containsKey(key)) {
                int num = fixPayMap.containsKey(key) ? fixPayMap.get(key) : 0;
                return (double) (num);
            } else {
                return (double) 0.0F;
            }

        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            //ex.printStackTrace();
        }
        return (double) 0.0F;
    }


    /**
     * 查询生效日期当月离职的人数，按"人员ID_生效年月"为 key 缓存到 tempMap。
     * <p>
     * 通过 CT_REC_ApplicantBeisen（北森应聘表）关联 T_HR_RESIGNBIZBILL（离职单据），
     * 统计招聘渠道入职的员工在生效日期当月离职的人数。
     * @param ctx                上下文
     * @param tempMap            临时缓存 Map
     * @param mainTableName      计算表对象名
     * @param mainTableRowFilter 计算表数据行过滤条件
     * @param lzZhiMapKey        缓存 key
     * @throws BOSException 数据库异常
     * @throws SQLException SQL异常
     */
    private static void getLiZhiPersonNum(Context ctx, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter, String lzZhiMapKey) throws BOSException, SQLException {
        Map<String, Integer> lzFixPayMap = (Map) tempMap.get(lzZhiMapKey);
        if(lzFixPayMap==null){
            StringBuilder sql = new StringBuilder();
            sql.append(" /*dialect*/ ");
            // 主查询：按核算表和生效月份分组统计离职人数
            sql.append(" SELECT mt.fpersonid,substring(convert(varchar,mt.FEffectDate,120),0,8) FEffectDate,count(abt.pid) pNum from ").append(mainTableName).append(" mt ");
            // 关联子查询：通过北森应聘表匹配到人员，再关联其最近一次离职记录
            sql.append(" left join ( select ab.CFRecruitOwnerID,p.fid pid,t.fbizDate bizDate ");
            sql.append(" from CT_REC_ApplicantBeisen ab ");
            sql.append(" inner join T_REC_ResumeBaseRec rb on rb.CFCANDIDATEID = ab.CFCANDIDATEID ");
            sql.append(" inner join t_bd_person p on isnull(p.FIDCARDNO,p.FPASSPORTNO)=isnull(rb.FIdentityCardNo,rb.FPassportNo) ");
            // 取每个人员最近一次离职记录（ROW_NUMBER + rn=1）
            sql.append(" left join ( ");
            sql.append("         SELECT FPERSONID, FBIZDATE ");
            sql.append(" FROM ( ");
            sql.append("         SELECT ");
            sql.append("         e.FPERSONID, ");
            sql.append("         e.FBIZDATE, ");
            sql.append("         ROW_NUMBER() OVER (PARTITION BY e.FPERSONID ORDER BY e.FBIZDATE DESC) AS rn ");
            sql.append("         FROM T_HR_RESIGNBIZBILLENTRY e ");
            sql.append("         LEFT JOIN T_HR_RESIGNBIZBILL b ON b.fid = e.FBillID ");
            sql.append("         where b.FBillState=3 ");
            sql.append("  ) t ");
            sql.append(" WHERE rn = 1) t on t.fpersonid=p.fid ) abt on abt.CFRecruitOwnerID=mt.fpersonid ");
            // 离职日期在生效日期当月范围内：[当月第一天, 下月第一天)
            sql.append(" AND abt.bizDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, mt.FEffectDate), 0)");              // 当月第一天 00:00:00.000
            sql.append(" AND abt.bizDate < DATEADD(MONTH, DATEDIFF(MONTH, 0, mt.FEffectDate) + 1, 0) ");           // 下个月第一天 00:00:00.000
            sql.append(" AND mt.fid in(").append(mainTableRowFilter).append(") group by mt.fpersonid,substring(convert(varchar,mt.FEffectDate,120),0,8) ");
            IRowSet rs = DbUtil.executeQuery(ctx,sql.toString());
            lzFixPayMap = new HashMap<>();
            while (rs.next()) {
                //获取人数
                String fpersonid = rs.getString("fpersonid");
                String FEffectDate = rs.getString("FEffectDate");
                int pNum = rs.getInt("pNum");
                lzFixPayMap.put(fpersonid+"_"+FEffectDate,pNum);
            }
            tempMap.put(lzZhiMapKey, lzFixPayMap);
        }
    }
    /**
     * 查询生效日期当月入职的人数，按"人员ID_生效年月"为 key 缓存到 tempMap。
     * <p>
     * 通过 CT_REC_ApplicantBeisen（北森应聘表）关联 T_HR_EmpEnrollBizBill（入职单据），
     * 统计招聘渠道入职的员工在生效日期当月入职的人数。
     * @param ctx                上下文
     * @param tempMap            临时缓存 Map
     * @param mainTableName      计算表对象名
     * @param mainTableRowFilter 计算表数据行过滤条件
     * @param ruZhiMapKey        缓存 key
     * @throws BOSException 数据库异常
     * @throws SQLException SQL异常
     */
    private static void getRuZhiPersonNum(Context ctx, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter, String ruZhiMapKey) throws BOSException, SQLException {
        Map<String, Integer> fixPayMap = (Map) tempMap.get(ruZhiMapKey);
        if(fixPayMap==null){
            StringBuilder sql = new StringBuilder();
            sql.append(" /*dialect*/ ");
            // 主查询：按核算表和生效月份分组统计入职人数
            sql.append(" SELECT mt.fpersonid,substring(convert(varchar,mt.FEffectDate,120),0,8) FEffectDate,count(abt.pid) pNum from ").append(mainTableName).append(" mt ");
            // 关联子查询：通过北森应聘表匹配到人员，再关联其最近一次入职记录
            sql.append(" left join ( select ab.CFRecruitOwnerID,p.fid pid,t.fbizDate bizDate ");
            sql.append(" from CT_REC_ApplicantBeisen ab ");
            sql.append(" inner join T_REC_ResumeBaseRec rb on rb.CFCANDIDATEID = ab.CFCANDIDATEID ");
            sql.append(" inner join t_bd_person p on isnull(p.FIDCARDNO,p.FPASSPORTNO)=isnull(rb.FIdentityCardNo,rb.FPassportNo) ");
            // 取每个人员最近一次入职记录（ROW_NUMBER + rn=1）
            sql.append(" left join ( ");
            sql.append("         SELECT FPERSONID, FBIZDATE ");
            sql.append(" FROM ( ");
            sql.append("         SELECT ");
            sql.append("         e.FPERSONID, ");
            sql.append("         e.FBIZDATE, ");
            sql.append("         ROW_NUMBER() OVER (PARTITION BY e.FPERSONID ORDER BY e.FBIZDATE DESC) AS rn ");
            sql.append("         FROM T_HR_EmpEnrollBizBillEntry e ");
            sql.append("         LEFT JOIN T_HR_EmpEnrollBizBill b ON b.fid = e.FBillID ");
            sql.append("         where b.FBillState=3 ");
            sql.append("  ) t ");
            sql.append(" WHERE rn = 1) t on t.fpersonid=p.fid ) abt on abt.CFRecruitOwnerID=mt.fpersonid ");
            // 入职日期在生效日期当月范围内：[当月第一天, 下月第一天)
            sql.append(" AND abt.bizDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, mt.FEffectDate), 0)");              // 当月第一天 00:00:00.000
            sql.append(" AND abt.bizDate < DATEADD(MONTH, DATEDIFF(MONTH, 0, mt.FEffectDate) + 1, 0) ");           // 下个月第一天 00:00:00.000
            sql.append(" AND mt.fid in(").append(mainTableRowFilter).append(") group by mt.fpersonid,substring(convert(varchar,mt.FEffectDate,120),0,8) ");
            IRowSet rs = DbUtil.executeQuery(ctx,sql.toString());
            fixPayMap = new HashMap<>();
            while (rs.next()) {
                //获取人数
                String fpersonid = rs.getString("fpersonid");
                String FEffectDate = rs.getString("FEffectDate");
                int pNum = rs.getInt("pNum");
                fixPayMap.put(fpersonid+"_"+FEffectDate,pNum);
            }
            tempMap.put(ruZhiMapKey, fixPayMap);
        }
    }

    /**
     * 查询生效日期当月转正的人数，按"人员ID_生效年月"为 key 缓存到 tempMap。
     * <p>
     * 通过 CT_REC_ApplicantBeisen（北森应聘表）关联 T_HR_EMPHIREBIZBILL（转正单据），
     * 统计招聘渠道入职的员工在生效日期当月转正的人数。
     * @param ctx                上下文
     * @param tempMap            临时缓存 Map
     * @param mainTableName      计算表对象名
     * @param mainTableRowFilter 计算表数据行过滤条件
     * @param ruZhiMapKey        缓存 key
     * @throws BOSException 数据库异常
     * @throws SQLException SQL异常
     */
    private static void getZhuanZhengPersonNum(Context ctx, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter, String ruZhiMapKey) throws BOSException, SQLException {
        Map<String, Integer> fixPayMap = (Map) tempMap.get(ruZhiMapKey);
        if(fixPayMap==null){
            StringBuilder sql = new StringBuilder();
            sql.append(" /*dialect*/ ");
            // 主查询：按核算表和生效月份分组统计转正人数
            sql.append(" SELECT mt.fpersonid,substring(convert(varchar,mt.FEffectDate,120),0,8) FEffectDate,count(abt.pid) pNum from ").append(mainTableName).append(" mt ");
            // 关联子查询：通过北森应聘表匹配到人员，再关联其最近一次转正记录
            sql.append(" left join ( select ab.CFRecruitOwnerID,p.fid pid,t.fbizDate bizDate ");
            sql.append(" from CT_REC_ApplicantBeisen ab ");
            sql.append(" inner join T_REC_ResumeBaseRec rb on rb.CFCANDIDATEID = ab.CFCANDIDATEID ");
            sql.append(" inner join t_bd_person p on isnull(p.FIDCARDNO,p.FPASSPORTNO)=isnull(rb.FIdentityCardNo,rb.FPassportNo) ");
            // 取每个人员最近一次转正记录（ROW_NUMBER + rn=1）
            sql.append(" left join ( ");
            sql.append("         SELECT FPERSONID, FBIZDATE ");
            sql.append(" FROM ( ");
            sql.append("         SELECT ");
            sql.append("         e.FPERSONID, ");
            sql.append("         e.FBIZDATE,e.FEnrollDate, ");
            sql.append("         ROW_NUMBER() OVER (PARTITION BY e.FPERSONID ORDER BY e.FBIZDATE DESC) AS rn ");
            sql.append("         FROM T_HR_EMPHIREBIZBILLENTRY e ");
            sql.append("         LEFT JOIN T_HR_EMPHIREBIZBILL b ON b.fid = e.FBillID ");
            sql.append("         where b.FBillState=3 ");
            sql.append("  ) t ");
            sql.append(" WHERE rn = 1) t on t.fpersonid=p.fid ) abt on abt.CFRecruitOwnerID=mt.fpersonid ");
            // 转正日期在生效日期当月范围内：[当月第一天, 下月第一天)
            sql.append(" AND abt.bizDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, mt.FEffectDate), 0)");              // 当月第一天 00:00:00.000
            sql.append(" AND abt.bizDate < DATEADD(MONTH, DATEDIFF(MONTH, 0, mt.FEffectDate) + 1, 0) ");           // 下个月第一天 00:00:00.000
            sql.append(" AND mt.fid in(").append(mainTableRowFilter).append(") group by mt.fpersonid,substring(convert(varchar,mt.FEffectDate,120),0,8) ");
            IRowSet rs = DbUtil.executeQuery(ctx,sql.toString());
            fixPayMap = new HashMap<>();
            while (rs.next()) {
                //获取人数
                String fpersonid = rs.getString("fpersonid");
                String FEffectDate = rs.getString("FEffectDate");
                int pNum = rs.getInt("pNum");
                fixPayMap.put(fpersonid+"_"+FEffectDate,pNum);
            }
            tempMap.put(ruZhiMapKey, fixPayMap);
        }
    }


    /**
     * 获取生效日期的月份（yyyy-MM 格式）。
     * <p>
     * 优先从 tempMap 中以 "getEffect_" + id 为 key 查找缓存；
     * 缓存未命中时，一次性批量查询 mainTableRowFilter 范围内所有行的 FEffectDate，
     * 逐行以 "getEffect_" + fid 为 key 写入 tempMap，后续同一批次其他行直接命中缓存。
     * @param ctx                上下文
     * @param tempMap            临时缓存 Map
     * @param mainTableName      计算表对象名
     * @param mainTableRowFilter 计算表数据行过滤条件（用于批量加载）
     * @param id                 当前数据行 FID
     * @return 生效日期对应的 yyyy-MM 格式月份字符串，若未查到则为空字符串
     * @throws BOSException 数据库异常
     * @throws SQLException SQL异常
     */
    private static String getEffect(Context ctx, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter, String id) throws BOSException, SQLException {
        String cacheKey = "getEffect_" + id;
        if (tempMap.containsKey(cacheKey)) {
            return (String) tempMap.get(cacheKey);
        }
        IRowSet rowSet = DbUtil.executeQuery(ctx, " SELECT mt.fid,mt.fpersonid,mt.FEffectDate from " + mainTableName + " mt where mt.fid in("+mainTableRowFilter+")");
        String Effect = "";
        while (rowSet.next()) {
            String fid = rowSet.getString("fid");
            LocalDate effectDate = rowSet.getDate("FEffectDate").toLocalDate();
            Effect = effectDate.format(DateTimeFormatter.ofPattern("yyyy-MM"));
            String Key = "getEffect_" + fid;
            tempMap.put(Key, Effect);
        }

        return (String) tempMap.getOrDefault(cacheKey, "");
    }









    /**
     * 获取适用薪酬方案名称（fname_l2）。
     * <p>
     * 通过计算表关联 T_HR_SBatchSubmitShemeBill 和 T_HR_SCalSubmitScheme，
     * 查询当前计算范围对应的薪酬方案名称，结果以"name"为 key 缓存。
     * @param ctx                上下文
     * @param paramMap           参数（含 FPERSONID、FID）
     * @param tempMap            临时缓存 Map
     * @param mainTableName      计算表对象名
     * @param mainTableRowFilter 计算表数据行过滤条件
     * @return 方案名称，未找到则返回空字符串
     */
    public String getApplicablePlan(Context ctx, Map<String, Object> paramMap, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter) {
        try {
            //计算的员工id
            String personId = (String) paramMap.get(mainTableName.toUpperCase() + "_FPERSONID");
            //计算的数据行
            String id = (String) paramMap.get(mainTableName.toUpperCase() + "_FID");
            //根据计算范围初始化薪酬项目信息
            String fixPayMapKey = "getApplicablePlan_SchemeName";

            if (tempMap.get(fixPayMapKey) == null) {
                StringBuilder sql = new StringBuilder();
                sql.append(" select sss.fname_l2 from "+mainTableName+" sbe ");
                sql.append(" left join T_HR_SBatchSubmitShemeBill ssb on ssb.fid=sbe.FBillID ");
                sql.append(" left join T_HR_SCalSubmitScheme sss on sss.fid=ssb.FSubmitSchemeID ");
                sql.append(" where sbe.fid in(" + mainTableRowFilter + ")");
                IRowSet rs = DbUtil.executeQuery(ctx, sql.toString());
                if (rs.next()) {
                    Map<String, String> objectMap = new HashMap<>();
                    objectMap.put("name", rs.getString("fname_l2"));
                    tempMap.put(fixPayMapKey, objectMap);
                }
            }
            //获取薪酬项目值
            Map<String, String> fixPayMap = (Map) tempMap.get(fixPayMapKey);
            String key = "name";
            if (fixPayMap.containsKey(key)) {
                String schemeName = fixPayMap.get(key);

                return schemeName;
            } else {
                return "";
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            //e.printStackTrace();
            return "";
        }
    }

    /**
     * 获取薪酬档案中指定薪资项目的金额。
     * <p>
     * 根据人员 ID 和薪酬项目名称，从 T_HR_SFIXADJUSTSALARY 表中查询固定薪酬数据。
     * 结果以 "personId_cmpItem" 为 key 缓存到 tempMap，后续同一计算范围直接复用。
     * @param ctx                上下文
     * @param paramMap           参数（含 FPERSONID、FID）
     * @param tempMap            临时缓存 Map
     * @param mainTableName      计算表对象名
     * @param mainTableRowFilter 计算表数据行过滤条件
     * @param cmpItem            薪酬项目名称（对应 T_HR_SCMPITEM.FNAME_L2）
     * @param isFixed            是否固定薪酬（0=按FEffectDate匹配, 非0=按FEffectDate匹配；预留扩展）
     * @return 薪资项目金额，若人员或项目不存在则返回 0.0
     */
    public double getItemSalary(Context ctx, Map<String, Object> paramMap, HashMap<String, Object> tempMap, String mainTableName, String mainTableRowFilter,
                                String cmpItem, double isFixed) {
        try {
            //计算的员工id
            String personId = (String) paramMap.get(mainTableName.toUpperCase() + "_FPERSONID");
            //计算的数据行
            String id = (String) paramMap.get(mainTableName.toUpperCase() + "_FID");

            //根据计算范围初始化薪酬项目信息
            String fixPayMapKey = "getItemSalary_fixPayMap_" + isFixed;
            if (!StringUtils.isEmpty(cmpItem) && personId != null) {
                if (tempMap.get(fixPayMapKey) == null) {
                    tempMap.put(fixPayMapKey, this.initFixPayForMoneyMap(ctx, mainTableName, isFixed, mainTableRowFilter));
                }
                //获取薪酬项目值
                Map<String, BigDecimal> fixPayMap = (Map) tempMap.get(fixPayMapKey);
                String key = personId + "_" + cmpItem;
                if (fixPayMap.containsKey(key)) {
                    BigDecimal money = fixPayMap.containsKey(key) ? (BigDecimal) fixPayMap.get(key) : new BigDecimal(0);
                    double pay = money.doubleValue();
                    return pay;
                } else {
                    return (double) 0.0F;
                }
            } else {
                return (double) 0.0F;
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            //e.printStackTrace();
            return (double) 0.0F;
        }
    }

    /**
     * 初始化固定薪酬数据 Map，以 "personId_cmpItem" 为 key，金额为 value。
     * <p>
     * 查询 T_HR_SFIXADJUSTSALARY（固定调整薪酬表），按生效日期匹配核算表中的薪酬项目。
     * 查询结果按 type 优先级排序：type=1（相同组织）优先于 type=0（无组织限制），
     * 同一 key 仅保留首次出现的记录（优先级最高的）。
     * @param ctx                上下文
     * @param mainTableName      计算表对象名
     * @param isFixed            是否固定薪酬（0=按FEffectDate匹配, 非0=按FEffectDate匹配；预留扩展）
     * @param mainTableRowFilter 计算表数据行过滤条件
     * @return key 为 "personId_cmpItem"，value 为对应金额的 Map
     * @throws Exception 数据库异常
     */
    public Map<String, BigDecimal> initFixPayForMoneyMap(Context ctx, String mainTableName, double isFixed, String mainTableRowFilter) throws Exception {

        StringBuilder sb = new StringBuilder();
        String effectDayField = "";
        String key = null;
        String personId = "";
        String cmpItem = "";
        Map<String, BigDecimal> fixPayMap = new HashMap();
        Set<String> set = new HashSet();
        if (isFixed == (double) 0.0F) {
            effectDayField = "calTable.FEffectDate";
        } else {
            effectDayField = "calTable.FEffectDate";
        }

        sb.append(" SELECT DISTINCT CALTABLE.FPERSONID as personId, FIX.FMONEY MONEY, FIX.FCURRENCYID, ");
        sb.append(" CMPITEM.FNAME_L2 CMPITEM,FIX.FEFFECTDAY, ");
        // type: 0=组织为空(通用), 1=组织匹配(优先), 2=组织不匹配(排除)
        sb.append(" ( case when (fix.fpayhrorgunitid is null or fix.fpayhrorgunitid in ('')) then 0  when ( calTable.FHrOrgUnitID= fix.fpayhrorgunitid) then 1 else 2 end ) as type").append("\r\n");
        sb.append(" FROM " + mainTableName + " CALTABLE ");
        sb.append(" INNER JOIN T_HR_SFIXADJUSTSALARY FIX ON CALTABLE.FPERSONID=FIX.FPERSONID AND (FIX.FCurrencyID = CALTABLE.FCurrencyID OR FIX.FCurrencyID IS NULL)");
        sb.append(" LEFT JOIN T_HR_SCMPITEM CMPITEM ON CMPITEM.FID=FIX.FCMPITEMID ");
        sb.append(" WHERE FIX.feffectday <= ").append(effectDayField).append(" AND FIX.fleffectday >= ").append(effectDayField);
        sb.append(" AND CALTABLE.fid in(").append(mainTableRowFilter).append(")");

        IRowSet rs = DbUtil.executeQuery(ctx, sb.toString());
        List<Map<String, Object>> dataList = this.getDataFromExecuteQuery(rs);
        Iterator<Map<String, Object>> it = dataList.iterator();
        while (it.hasNext()) {
            Map<String, Object> data = (Map) it.next();
            personId = (String) data.get("personId");
            cmpItem = (String) data.get("CMPITEM");
            key = personId + "_" + cmpItem;
            if (!set.contains(key)) {
                set.add(key);
                BigDecimal money = (BigDecimal) data.get("MONEY");
                fixPayMap.put(key, money);
            }
        }
        return fixPayMap;
    }

    /**
     * 将 IRowSet 查询结果按优先级排序后转换为 List&lt;Map&gt;。
     * <p>
     * 排序规则：type=1（相同组织）的记录优先，type=0（无组织限制）的次之，type=2（组织不匹配）的排除。
     * 同一人员同一薪酬项目的 key 只保留首次出现（即优先级最高）的记录。
     * @param executeQuery 查询结果集
     * @return 按优先级排序后的数据列表
     * @throws SQLException SQL异常
     */
    public List<Map<String, Object>> getDataFromExecuteQuery(IRowSet executeQuery) throws SQLException {
        Map<String, Object> map = null;
        List<Map<String, Object>> dataList = null;
        Map<String, List<Map<String, Object>>> mapList = null;
        Map<String, List<Map<String, Object>>> mapListOne = null;
        Map<String, List<Map<String, Object>>> mapListZero = null;
        List<Map<String, Object>> list = null;
        List<Map<String, Object>> oneList = null;
        List<Map<String, Object>> zeroList = null;
        if (null != executeQuery) {
            String personId = null;
            dataList = new ArrayList();
            mapList = new HashMap();
            mapListOne = new HashMap();
            mapListZero = new HashMap();

            while (executeQuery.next()) {
                map = this.executeQueryToMap(executeQuery);
                personId = executeQuery.getString("personId");
                int type = executeQuery.getInt("type");
                if (mapList.containsKey(personId)) {
                    list = (List) mapList.get(personId);
                    list.add(map);
                } else {
                    list = new ArrayList();
                    list.add(map);
                    mapList.put(personId, list);
                }

                // type=1: 组织匹配，优先使用
                if (type == 1) {
                    if (mapListOne.containsKey(personId)) {
                        oneList = (List) mapListOne.get(personId);
                        oneList.add(map);
                    } else {
                        oneList = new ArrayList();
                        oneList.add(map);
                        mapListOne.put(personId, oneList);
                    }
                // type=0: 无组织限制，次优
                } else if (type == 0) {
                    if (mapListZero.containsKey(personId)) {
                        zeroList = (List) mapListZero.get(personId);
                        zeroList.add(map);
                    } else {
                        zeroList = new ArrayList();
                        zeroList.add(map);
                        mapListZero.put(personId, zeroList);
                    }
                }
                // type=2（组织不匹配）排除，不加入结果
            }

            List<Map<String, Object>> var21 = null;

            // 合并结果：先加入 type=1（组织匹配），再加入 type=0（无组织限制）
            // 后续去重逻辑会保留首次出现的记录，从而实现优先级
            for (String str : mapList.keySet()) {
                List<Map<String, Object>> var22 = (List) mapList.get(str);
                if (mapListOne.containsKey(str)) {
                    dataList.addAll((Collection) mapListOne.get(str));
                }

                if (mapListZero.containsKey(str)) {
                    dataList.addAll((Collection) mapListZero.get(str));
                }
            }
        }

        return (List<Map<String, Object>>) (null != dataList && !dataList.isEmpty() ? dataList : new ArrayList(0));
    }

    /**
     * 将 IRowSet 当前行转换为 Map，提取固定薪酬相关字段。
     * @param executeQuery 查询结果集（已定位到某一行）
     * @return 包含 personId、MONEY、FCURRENCYID、CMPITEM、FEFFECTDAY 的 Map
     * @throws SQLException SQL异常
     */
    public Map<String, Object> executeQueryToMap(IRowSet executeQuery) throws SQLException {
        Map<String, Object> map = new HashMap();
        map.put("personId", executeQuery.getString("personId"));
        map.put("MONEY", executeQuery.getBigDecimal("MONEY") == null ? new BigDecimal(0) : executeQuery.getBigDecimal("MONEY"));
        map.put("FCURRENCYID", executeQuery.getString("FCURRENCYID"));
        map.put("CMPITEM", executeQuery.getString("CMPITEM"));
        map.put("FEFFECTDAY", executeQuery.getDate("FEFFECTDAY"));
        return map;
    }
}
