|
|
@@ -0,0 +1,691 @@
|
|
|
+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<Map>。
|
|
|
+ * <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;
|
|
|
+ }
|
|
|
+}
|