package com.yonyou.hrcloud.pm.ps.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yonyou.hrcloud.adder.context.AppContext;
import com.yonyou.hrcloud.adder.data.jdbc.DialectHelper;
import com.yonyou.hrcloud.adder.exception.AdderBusinessException;
import com.yonyou.hrcloud.adder.model.param.PagerRequest;
import com.yonyou.hrcloud.adder.model.param.Sorter;
import com.yonyou.hrcloud.adder.model.query.Condition;
import com.yonyou.hrcloud.adder.model.query.Operator;
import com.yonyou.hrcloud.pm.base.model.*;
import com.yonyou.hrcloud.pm.base.service.IDimService;
import com.yonyou.hrcloud.pm.base.service.IGradeService;
import com.yonyou.hrcloud.pm.base.service.IPeriodService;
import com.yonyou.hrcloud.pm.base.service.IScoreRuleService;
import com.yonyou.hrcloud.pm.base.service.ITagService;
import com.yonyou.hrcloud.pm.common.model.CommonValue;
import com.yonyou.hrcloud.pm.common.model.PmStaff;
import com.yonyou.hrcloud.pm.common.model.CommonValue.EnumWorkStep;
import com.yonyou.hrcloud.pm.helper.ListHelper;
import com.yonyou.hrcloud.pm.helper.LoggerDecorator;
import com.yonyou.hrcloud.pm.helper.OrgHelper;
import com.yonyou.hrcloud.pm.helper.StaffHelper;
import com.yonyou.hrcloud.pm.helper.Toolkit;
import com.yonyou.hrcloud.pm.ps.dao.ISchemeDao;
import com.yonyou.hrcloud.pm.ps.dao.ISheetDao;
import com.yonyou.hrcloud.pm.ps.model.*;
import com.yonyou.hrcloud.pm.ps.service.IEvaAppraiserService;
import com.yonyou.hrcloud.pm.ps.service.IEvaGroupService;
import com.yonyou.hrcloud.pm.ps.service.IEvaSettingService;
import com.yonyou.hrcloud.pm.ps.service.ISchemeService;
import com.yonyou.hrcloud.pm.ps.service.IExclQueryService;

import com.yonyou.iuap.utils.PropertyUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 绩效方案实现层
 *
 * @author Flysea
 */
@Service
@Transactional
public class SchemeServiceImpl implements ISchemeService {

    @Resource
    public com.yonyou.hrcloud.adder.service.IGenericService daoex;

    @Resource
    public ISchemeDao dao;

    @Resource
    public IPeriodService periodSrv;

    @Resource
    public IEvaGroupService groupSrv;

    @Resource
    public IDimService dimSrv;

    @Resource
    public IScoreRuleService scoreRuleSrv;

    @Resource
    public IGradeService gradeSrv;

    @Resource
    public ISheetDao daoSheet;

    @Resource
    public IEvaAppraiserService evaApprSrv;

    @Resource
    IEvaSettingService evaSettingService;
    
    @Resource
    ITagService tagSrv;
    
    @Resource
    IExclQueryService iExclQueryService;
    
    protected static final Logger logger = new LoggerDecorator(SchemeServiceImpl.class);

    @Override
    public List<Scheme> querySchemeByConditon(Condition cond, Sorter sort, Pageable pageable) {
        if (pageable == null)
			pageable = new PagerRequest(0, 100);
        if (sort != null)
            ((PagerRequest) pageable).setSort(sort);
        List<Scheme> objs = daoex.findPage(Scheme.class, cond, pageable).getContent();

        for (Scheme obj : objs) {
            obj.setSchememodename(CommonValue.EnumSchemeMode.valueOf(obj.getSchememode()).getDescription());
            obj.setSchemestatename(CommonValue.EnumSchemeState.values()[obj.getSchemestate()].getDescription());
        }
        return objs;
    }

    @Override
    @Transactional(readOnly = true)
    public List<Scheme> querySchemeList(Condition cond, Sorter sort, Pageable pageable) {
        if (cond == null)
            cond = new Condition();
        String userid = AppContext.getContext().getUserId();
        String runtime = PropertyUtil.getPropertyByKey("runtime", "prod");
        if ("dev".equals(runtime))
            cond.addExpression("creator", userid);
        else
            OrgHelper.setOrgCondition(cond, CommonValue.EnumServiceCode.SCHEME.getCode());
        cond.addExpression("schememode", CommonValue.EnumSchemeMode.pm_sum.getIndex(), Operator.LESS);
        cond.addExpression("schememode", CommonValue.EnumSchemeMode.pm_pbc.getIndex(), Operator.GREATEREQUAL);
        cond.addExpression("tenantid", AppContext.getContext().getScope());
        List<Scheme> schemeList = querySchemeByConditon(cond, sort, pageable);
		Map<String, Period> periodMap = new HashMap<>();
        for (Scheme obj : schemeList) {
			Period p = null;
			if (!periodMap.containsKey(obj.getPeriodid())) {
				p = periodSrv.queryPeriodByID(obj.getPeriodid());
				periodMap.put(obj.getPeriodid(), p);
			} else
				p = periodMap.get(obj.getPeriodid());
            obj.setPeriodname(p.getPeriodname());
            if (obj.getSchemestate() <= CommonValue.EnumSchemeState.State2.getIndex())
                obj.setPercent(0);
            else if (obj.getSchemestate() == CommonValue.EnumSchemeState.State4.getIndex()
                    || obj.getSchemestate() == CommonValue.EnumSchemeState.State6.getIndex()
                    || obj.getSchemestate() >= CommonValue.EnumSchemeState.State8.getIndex())
                obj.setPercent(100);
            else if (obj.getSchemestate() == CommonValue.EnumSchemeState.State3.getIndex()) {
                // 填报完成并审核通过人数与总人数的比例
                int percent = daoSheet.queryCompletionRatio(obj.getId());
                obj.setPercent(percent);
            } else if (obj.getSchemestate() == CommonValue.EnumSchemeState.State5.getIndex()) {
                // 各轮打分都完成的人数与总人数的比例
                int percent = daoSheet.queryAppraiseRatio(obj.getId());
                obj.setPercent(percent);
            } else if (obj.getSchemestate() == CommonValue.EnumSchemeState.State7.getIndex()) {
                // 各轮审核都完成的人数与总人数的比例
                int percent = daoSheet.queryResultRatio(obj.getId());
                obj.setPercent(percent);
            }
        }
		periodMap = null;
        return schemeList;
    }

	@Override
	@Transactional(readOnly = true)
	public Page<Scheme> querySchemeListByConfig(JSONObject jsonObject) {
		StopWatch stopWatch = new StopWatch("pm:querySchemeListByConfig");
		stopWatch.start("1");
		Condition condObj = new Condition();
		condObj.addExpression("schememode", CommonValue.EnumSchemeMode.pm_sum.getIndex(), Operator.LESS);
		condObj.addExpression("schememode", CommonValue.EnumSchemeMode.pm_pbc.getIndex(), Operator.GREATEREQUAL);
		condObj.addExpression("tenantid", AppContext.getContext().getScope());
		String periodcode = jsonObject.getString("periodcode");
		List<Integer> integers = new ArrayList<>();
		String schemestate = jsonObject.getString("schemestate");
		if (!StringUtils.isEmpty(schemestate)) {
			String[] schemestates = schemestate.split(",");
			for (String s : schemestates) {
				Integer integer = Integer.valueOf(s);
				integers.add(integer);
			}
		}
		String schemename = jsonObject.getString("schemename");
		Integer currentpage = jsonObject.getInteger("currentpage");
		Integer pagesize = jsonObject.getInteger("pagesize");
		Boolean isover = jsonObject.getBoolean("isover");
		String sortkey = jsonObject.getString("sortkey");
		String sortorder = jsonObject.getString("sortorder");
		String userid = AppContext.getContext().getUserId();
		String runtime = PropertyUtil.getPropertyByKey("runtime", "prod");
		stopWatch.stop();
		stopWatch.start("2");
		if ("dev".equals(runtime))
			condObj.addExpression("creator", userid);
//		else
//			OrgHelper.setOrgCondition(condObj, CommonValue.EnumServiceCode.SCHEME.getCode());
		stopWatch.stop();
		stopWatch.start("3");
		Sorter sortObj = new Sorter(Direction.DESC, Arrays.asList("tdate"));
		Sorter sortObj2 = new Sorter(Direction.DESC, Arrays.asList("periodcode", "creationtime"));
		sortObj = sortObj.and(sortObj2);
		if (sortkey != null)
			sortObj = new Sorter(Direction.fromString(sortorder), sortkey);
		if (isover) {
			// 已结束页签
			condObj.addExpression("isend", true);
		} else {
			condObj.addExpression("isend", false);
		}
		if (!StringUtils.isEmpty(periodcode)) {
			condObj.addExpression("periodcode", periodcode, Operator.EQUAL);
		}
		if (integers.size() > 0) {
			condObj.addExpression("schemestate", integers, Operator.IN);
		}
		if (!StringUtils.isEmpty(schemename)) {
			condObj.addExpression("schemename", schemename, Operator.LIKEANY);
		}
		PagerRequest pageable = new PagerRequest((currentpage == null ? 0 : currentpage),
				(pagesize == null ? 10 : pagesize), sortObj);
		Page<Scheme> schemes = daoex.findPage(Scheme.class, condObj, pageable);
        stopWatch.stop();
        //增加查找中期回顾方案列表
        //获取分页中的主方案列表
        List<Scheme> schemeList = schemes.getContent();
        if(CollectionUtils.isNotEmpty(schemeList)){
            stopWatch.start("4");
            buildSchemeInfo(schemeList);
            stopWatch.stop();
            List<String> schemeIdList = schemeList.stream().map(scheme -> scheme.getId()).collect(Collectors.toList());
            //在关联表中，根据主方案id，查询出关联的中期回顾方案数据
            Condition relationCondition = new Condition();
            relationCondition.addExpression("schemeid",schemeIdList,Operator.IN);
            relationCondition.addExpression("formulaschememode",CommonValue.EnumSchemeMode.pm_mtr.getIndex());
            List<SchemeRelation> relationList = daoex.find(SchemeRelation.class, relationCondition, null);
            if(CollectionUtils.isNotEmpty(relationList)){
                //获取中期回顾方案的id集合，查询方案信息
                List<String> formulaSchemeIdList = relationList.stream().map(SchemeRelation::getFormulaschemeid)
                        .collect(Collectors.toList());
                Condition mtrSchemeCondition = new Condition();
                mtrSchemeCondition.addExpression("id",formulaSchemeIdList.toArray(new String[formulaSchemeIdList.size()]),Operator.IN);
                List<Scheme> mtrSchemeList = daoex.find(Scheme.class,mtrSchemeCondition,sortObj);
                buildSchemeInfo(mtrSchemeList);
                Map<String, Scheme> mtrSchemeIdMap = mtrSchemeList.stream().collect(Collectors.toMap(Scheme::getId, Function.identity()));
                Map<String, List<String>> schemeAndMtrIdMap = relationList.stream().collect(Collectors.groupingBy(
                        SchemeRelation::getSchemeid, Collectors.mapping(SchemeRelation::getFormulaschemeid, Collectors.toList())));
                schemeList.forEach(scheme -> {
                    List<String> formulaIdList = schemeAndMtrIdMap.get(scheme.getId());
                    if(CollectionUtils.isNotEmpty(formulaIdList)){
                        formulaIdList.forEach(formulaId->{
                            if(mtrSchemeIdMap.get(formulaId) != null){
                                mtrSchemeIdMap.get(formulaId).setParentId(scheme.getId());
                            }
                        });
                    }
                });
                schemeList.addAll(mtrSchemeList);
            }
        }
		if (stopWatch.getTotalTimeSeconds() > 1.0) {
			logger.error("pm:querySchemeListByConfig " + stopWatch.prettyPrint());
			logger.error("pm:querySchemeListByConfig " + condObj.toString() + ";" + pageable.toString());
		}
		else
			logger.debug("pm:querySchemeListByConfig " + stopWatch.prettyPrint());
		return schemes;
	}

	/**
	 * 封装方案的期间名称和完成率等信息
	 * 
	 * @param schemes
	 */
	private void buildSchemeInfo(List<Scheme> schemes){
        for (Scheme obj : schemes) {
            Period p = daoex.load(Period.class, obj.getPeriodid());
            obj.setPeriodname(p.getPeriodname());
            if (obj.getSchemestate() <= CommonValue.EnumSchemeState.State2.getIndex())
                obj.setPercent(0);
            else if (obj.getSchemestate() == CommonValue.EnumSchemeState.State4.getIndex()
                    || obj.getSchemestate() == CommonValue.EnumSchemeState.State6.getIndex()
                    || obj.getSchemestate() >= CommonValue.EnumSchemeState.State8.getIndex()){
                obj.setPercent(100);
                if(obj.getSchemestate() == CommonValue.EnumSchemeState.State9.getIndex() 
                		&& !obj.isIsend() && obj.isIsresultconfirm()){
                	Integer percent = daoSheet.queryConfirmRatio(obj.getId());
                	if(percent == null)
                		percent = 0;
                	obj.setPercent(percent);
                }
            } else if (obj.getSchemestate() == CommonValue.EnumSchemeState.State3.getIndex()) {
                // 填报完成并审核通过人数与总人数的比例
                Integer percent = daoSheet.queryCompletionRatio(obj.getId());
                if (percent == null)
                    percent = 0;
                obj.setPercent(percent);
            } else if (obj.getSchemestate() == CommonValue.EnumSchemeState.State5.getIndex()) {
                // 各轮打分都完成的人数与总人数的比例
                int percent = daoSheet.queryAppraiseRatio(obj.getId());
                obj.setPercent(percent);
            } else if (obj.getSchemestate() == CommonValue.EnumSchemeState.State7.getIndex()) {
                // 各轮审核都完成的人数与总人数的比例
                int percent = daoSheet.queryResultRatio(obj.getId());
                obj.setPercent(percent);
            }
        }
    }

    @Override
    public Scheme querySchemeByID(String id, boolean isAll) throws AdderBusinessException {
        if (isAll)
            return querySchemeByID(id, true, true);
        else
            return querySchemeByID(id, false, false);
    }

    @Override
    public Scheme querySchemeByID(String id, boolean hasGroup, boolean hasAppraiser) throws AdderBusinessException {
        Condition condObj = new Condition();
        condObj.addExpression("id", id);
        //OrgHelper.setOrgCondition(condObj, CommonValue.EnumServiceCode.SCHEME.getCode()); // 去掉组织权限 ，
        List<Scheme> objs = daoex.find(Scheme.class, condObj, null);
        if (objs.size() > 0) {
            Scheme obj = objs.get(0);
            Period p = periodSrv.queryPeriodByID(obj.getPeriodid());
            obj.setPeriodname(p.getPeriodname());
            ScoreRule sr = scoreRuleSrv.queryScoreRuleByID(obj.getScoreruleid());
            if(sr != null) // 汇总方案没有评分规则id
            	obj.setScorerulename(sr.getName());
            // 添加方案组织，暂时不需要
            String userid = AppContext.getContext().getUserId();
            String staffid = StaffHelper.getStaffByUserId(userid);
            Map<String, PmStaff> staffList = StaffHelper.queryStaffByIds2(Arrays.asList(staffid),
                    false);
            // obj.setOrgid(staffList.get(staffid).getOrg_id());
            if (!hasGroup && !hasAppraiser)
                return obj;
            condObj = new Condition();
            if (hasGroup) {
                // 1、查询考核对象组信息
                condObj.addExpression("schemeid", obj.getId());
                List<EvaGroup> groups = groupSrv.queryEvaGroupByConditon(condObj, null);
                obj.setOGroups(groups);
            }
            if (hasAppraiser) {
                // 2、查询考核流程信息，一个维度审核人只能有一个
                condObj = new Condition();
                condObj.addExpression("schemeid", obj.getId());
                condObj.addExpression("workstep",
                        new Integer[]{EnumWorkStep.step1.getIndex(), EnumWorkStep.step2.getIndex()}, Operator.IN);
                Sorter sortObj = new Sorter(Direction.ASC, Arrays.asList("turn", "workstep"));
                List<EvaAppraiser> appraisers = daoex.find(EvaAppraiser.class, condObj, sortObj);
                List<String> idList = new ArrayList<String>();
                // 建立指标审核的Map<轮次,流程数据>
                Map<Integer, EvaAppraiser> approveMap = new HashMap<Integer, EvaAppraiser>();
                for (EvaAppraiser item : appraisers) {
                    if (item.getStaffid() != null && !idList.contains(item.getStaffid()))
                        idList.add(item.getStaffid());
                    if (item.getWorkstep() == EnumWorkStep.step1.getIndex())
                        approveMap.put(item.getTurn(), item);
                }
                // 根据人员获取名字
                staffList = StaffHelper.queryStaffByIds2(idList, false);
                List<EvaAppraiser> newAppr = new ArrayList<EvaAppraiser>();
                // 将同一轮次指标审核和评价合并成一条
                for (int i = 0; i < appraisers.size(); i++) {
                    EvaAppraiser appr = appraisers.get(i);
                    if (appr.getWorkstep() == EnumWorkStep.step2.getIndex()) {
                        Dimensionality dim = dimSrv.queryDimByID(appr.getDimid());
                        appr.setDimname(dim.getDimname());
                        if (approveMap.containsKey(appr.getTurn()))
                            appr.setIsapprove(true);
                        if (appr.getStaffid() != null && staffList.size() > 0)
                            appr.setStaffname(staffList.get(appr.getStaffid()).name);
                        newAppr.add(appr);
                    }
                }
                obj.setOEvaAppraiser(newAppr);
            }
            return obj;
        } else
            return null;
    }
    
    @Override
    public Scheme queryAuthorizedSchemeByID(String id, boolean isAll) throws AdderBusinessException {
    	// 查询有权限的方案
        if (isAll)
            return queryAuthorizedSchemeByID(id, true, true);
        else
            return queryAuthorizedSchemeByID(id, false, false);
    }
    /**
     * 查询有权限的方案
     * @param id
     * @param hasGroup
     * @param hasAppraiser
     * @return
     * @throws AdderBusinessException
     */
    @Override
    public Scheme queryAuthorizedSchemeByID(String id, boolean hasGroup, boolean hasAppraiser) throws AdderBusinessException {
        Condition condObj = new Condition();
        condObj.addExpression("id", id);
//        OrgHelper.setOrgCondition(condObj, CommonValue.EnumServiceCode.SCHEME.getCode());
        List<Scheme> objs = daoex.find(Scheme.class, condObj, null);
        if (objs.size() > 0) {
            Scheme obj = objs.get(0);
            Period p = periodSrv.queryPeriodByID(obj.getPeriodid());
            obj.setPeriodname(p.getPeriodname());
            ScoreRule sr = scoreRuleSrv.queryScoreRuleByID(obj.getScoreruleid());
            if(sr != null) // 汇总方案没有评分规则id
            	obj.setScorerulename(sr.getName());
            // 添加方案组织，暂时不需要
            String userid = AppContext.getContext().getUserId();
            String staffid = StaffHelper.getStaffByUserId(userid);
            Map<String, PmStaff> staffList = StaffHelper.queryStaffByIds2(Arrays.asList(staffid),
                    false);
            // obj.setOrgid(staffList.get(staffid).getOrg_id());
            if (!hasGroup && !hasAppraiser)
                return obj;
            condObj = new Condition();
            if (hasGroup) {
                // 1、查询考核对象组信息
                condObj.addExpression("schemeid", obj.getId());
                List<EvaGroup> groups = groupSrv.queryEvaGroupByConditon(condObj, null);
                obj.setOGroups(groups);
            }
            if (hasAppraiser) {
                // 2、查询考核流程信息，一个维度审核人只能有一个
                condObj = new Condition();
                condObj.addExpression("schemeid", obj.getId());
                condObj.addExpression("workstep",
                        new Integer[]{EnumWorkStep.step1.getIndex(), EnumWorkStep.step2.getIndex()}, Operator.IN);
                Sorter sortObj = new Sorter(Direction.ASC, Arrays.asList("turn", "workstep"));
                List<EvaAppraiser> appraisers = daoex.find(EvaAppraiser.class, condObj, sortObj);
                List<String> idList = new ArrayList<String>();
                // 建立指标审核的Map<轮次,流程数据>
                Map<Integer, EvaAppraiser> approveMap = new HashMap<Integer, EvaAppraiser>();
                for (EvaAppraiser item : appraisers) {
                    if (item.getStaffid() != null && !idList.contains(item.getStaffid()))
                        idList.add(item.getStaffid());
                    if (item.getWorkstep() == EnumWorkStep.step1.getIndex())
                        approveMap.put(item.getTurn(), item);
                }
                // 根据人员获取名字
                staffList = StaffHelper.queryStaffByIds2(idList, false);
                List<EvaAppraiser> newAppr = new ArrayList<EvaAppraiser>();
                // 将同一轮次指标审核和评价合并成一条
                for (int i = 0; i < appraisers.size(); i++) {
                    EvaAppraiser appr = appraisers.get(i);
                    if (appr.getWorkstep() == EnumWorkStep.step2.getIndex()) {
                        Dimensionality dim = dimSrv.queryDimByID(appr.getDimid());
                        appr.setDimname(dim.getDimname());
                        if (approveMap.containsKey(appr.getTurn()))
                            appr.setIsapprove(true);
                        if (appr.getStaffid() != null && staffList.size() > 0)
                            appr.setStaffname(staffList.get(appr.getStaffid()).name);
                        newAppr.add(appr);
                    }
                }
                obj.setOEvaAppraiser(newAppr);
            }
            return obj;
        } else
            return null;
    }

    @Override
    public void insert(Scheme scheme) {
        checkScheme(scheme);
        checkNameRepeat(scheme.getSchemename(), null);
		// 判断是否是价值观方案
        checkSchemeValues(scheme);
        daoex.insert(scheme);
        // 保存方案流程
        if (!CollectionUtils.isEmpty(scheme.getOEvaAppraiser())) {
            List<EvaAppraiser> newEvaAppraiser = cloneApprove(scheme);
            if (newEvaAppraiser.size() > 0)
                scheme.getOEvaAppraiser().addAll(newEvaAppraiser);
            daoex.insertBatch(scheme.getOEvaAppraiser());
        }
        saveSchemeFlow(scheme);
    }

    @Override
    public void update(Scheme scheme) {
        checkScheme(scheme);
        checkNameRepeat(scheme.getSchemename(), scheme.getId());
        Scheme schemeold = daoex.load(Scheme.class, scheme.getId());
        if (scheme.getSchemestate() == CommonValue.EnumSchemeState.State2.getIndex()) {
            // 方案在保存状态才更新子表
            Condition condObj = new Condition();
            condObj.addExpression("schemeid", scheme.getId());
            condObj.addExpression("workstep",
                    new Integer[]{EnumWorkStep.step1.getIndex(), EnumWorkStep.step2.getIndex()}, Operator.IN);
            dao.deleteAppraiser(condObj);
            if (!CollectionUtils.isEmpty(scheme.getOEvaAppraiser())) {
                List<EvaAppraiser> newEvaAppraiser = cloneApprove(scheme);
                if (newEvaAppraiser.size() > 0)
                    scheme.getOEvaAppraiser().addAll(newEvaAppraiser);

                daoex.insertBatch(scheme.getOEvaAppraiser());
            }
        }
        if (schemeold.isIsresultaudited() != scheme.isIsresultaudited()) {
            // 如果没有结果审核，检查是否设置了结果审核设置
            if (!scheme.isIsresultaudited()) {
                if (evaApprSrv.isExistWorkStep(scheme.getId(), EnumWorkStep.step3))
                    throw new AdderBusinessException("已存在结果审核设置，不能取消考核结果需要审核选项", "pm.i18n_core.ps.010");
            }
            // 调整pm_scheme_flow
            updateSchemeFlow(scheme);
        }
		if (schemeold.isIsallowfillup() != scheme.isIsallowfillup()) {
			// 检查是否存在sheet
			Condition condObj2 = new Condition();
			condObj2.addExpression("schemeid", scheme.getId());
			Pageable pageObj = new PagerRequest(0, 1, null);
			Page<Sheet> s = daoex.findPage(Sheet.class, condObj2, pageObj);
			if (s.hasContent())
				throw new AdderBusinessException("不能改变是否员工进行指标填报选项", "pm.i18n_pbc.ps.022");
		}
		// 判断是否是价值观方案
        if (scheme.getSchememode() == CommonValue.EnumSchemeMode.pm_sum.getIndex()) {
            scheme.setSchememode(CommonValue.EnumSchemeMode.pm_sum.getIndex());
        } else if (scheme.getSchememode() == CommonValue.EnumSchemeMode.pm_mtr.getIndex()) {
            scheme.setSchememode(CommonValue.EnumSchemeMode.pm_mtr.getIndex());
        } else {
			if (scheme.getId() != null && scheme.getSchememode() == CommonValue.EnumSchemeMode.pm_values.getIndex()
					&& scheme.isIsallowfillup()) {
				// 价值观改为PBC，不能修改允许填报状态
				throw new AdderBusinessException("不能修改方案填报状态", "pm.i18n_core.ps.088");
			}
            scheme.setSchememode(CommonValue.EnumSchemeMode.pm_pbc.getIndex());
            checkSchemeValues(scheme);
        }
        daoex.update(scheme);
    }

	@Override
	public void saveSchemeInfo(String schemeid, String schemename, String remark) {
		checkSchemeSimple(schemeid, schemename, remark);
		Scheme scheme = queryAuthorizedSchemeByID(schemeid, false);
		if (scheme == null)
			throw new AdderBusinessException("权限受限，请联系管理人员", "pm.i18n_core.system.001");
		checkNameRepeat(schemename, schemeid);
		List<String> attrs = new ArrayList<>();
		if (!StringUtils.isEmpty(schemename)) {
			attrs.add("schemename");
			scheme.setSchemename(schemename);
		}
		if (!StringUtils.isEmpty(remark)) {
			attrs.add("remark");
			scheme.setRemark(remark);
		}
		if (attrs.size() > 0)
			daoex.update(scheme, attrs);
		else
			throw new AdderBusinessException("方案数据不正确", "pm.i18n_core.ps.021");
	}

    @Override
    public void delete(String id) {
    	String dbType = DialectHelper.getDBType();
        dao.delete(id, dbType);
    }

    @Override
    public List<EvaAppraiser> queryEvaAppraiserByConditon(Condition cond, Sorter sort) {
        List<EvaAppraiser> objs = daoex.find(EvaAppraiser.class, cond, sort);
        return objs;
    }
	
	@Override
	public Scheme saveObjectAppraiser(JSONObject data) {
		String schemeid = data.getString("schemeid");
		if(StringUtils.isEmpty(schemeid)){
			throw new AdderBusinessException("参数不能为空", "pm.i18n_core.comm.002");
		}
		Scheme scheme = queryAuthorizedSchemeByID(schemeid,false);
		if(scheme == null){
			throw new AdderBusinessException("数据已不存在，请刷新再试", "pm.i18n_core.comm.004");
		}
		List<String> evaidlist = data.getObject("evaobject_ids", List.class); //所选考核对象id集合
		JSONArray appraiser_list = data.getJSONArray("objectAppraiser"); //考核人信息（类别/staffid/权重）
		if(evaidlist == null || evaidlist.size() <= 0 ||
				appraiser_list == null || appraiser_list.size() <= 0){
			throw new AdderBusinessException("参数不能为空", "pm.i18n_core.comm.002");
		}
		JSONArray approver_list = data.getJSONArray("objectApprover");  //审核人人员staffid 集合
		if (scheme.isIsallowfillup() || scheme.getIndisource() == CommonValue.EnumIndiSource.issued.getIndex()) { 
			if(approver_list == null || approver_list.size() <= 0 ){
				throw new AdderBusinessException("参数不能为空", "pm.i18n_core.comm.002");
			}
		}
		//修改前的删除操作
		Condition condition = new Condition();
		condition.addExpression("schemeid", schemeid);
		condition.addExpression("evaobjectid", evaidlist, Operator.IN);
		dao.deleteObjectAppraiser(condition);
		// 验证审核人
		if(scheme.isIsallowfillup() || scheme.getIndisource() == CommonValue.EnumIndiSource.issued.getIndex()){ 
			if (ListHelper.distinct(approver_list).size() < approver_list.size())
				throw new AdderBusinessException("指标审核人不能重复", "pm.i18n_pbc.ia.006");
		}
		boolean bFirst = true;
    	for(String evaobjectid : evaidlist){
			if (bFirst) {
				// 检查考核对象和传入的方案是否是一个
				EvaObject evaObject = daoex.load(EvaObject.class, evaobjectid);
				if (!schemeid.equals(evaObject.getSchemeid()))
					throw new AdderBusinessException("数据不正确", "pm.i18n_core.comm.003");
				bFirst = false;
			}
    		// 保存审核人
			if (scheme.isIsallowfillup() || scheme.getIndisource() == CommonValue.EnumIndiSource.issued.getIndex()) { // 只有允许填报的方案，才会保存审核人信息
				for (int i = 0; i < approver_list.size(); i++) {
	    			EvaSetting appraiser = new EvaSetting();
	    			String staffid = approver_list.getString(i);
					if (StringUtils.isEmpty(staffid)) {
						if (scheme.getIndisource() == CommonValue.EnumIndiSource.issued.getIndex())
							throw new AdderBusinessException("请设置指标下达人", "pm.i18n_pbc.ia.022");
						else
							throw new AdderBusinessException("指标审核人不能为空", "pm.i18n_pbc.ia.008");
					}
	    			appraiser.setStaffid(staffid);
	        		appraiser.setSchemeid(schemeid);
	        		appraiser.setWorkstep(CommonValue.EnumWorkStep.step1.getIndex());
	        		appraiser.setTurn(i+1);
	        		appraiser.setEvaobjectid(evaobjectid);
	        		appraiser.setSchemeid(schemeid);
	        		daoex.insert(appraiser);
	        	}	
    		}
    		// 保存考核人。
    		BigDecimal totalweight = new BigDecimal(0);
    		ArrayList<EvaSetting> apprlist = new ArrayList<EvaSetting>();
    		List<String> hasExitApprList = new ArrayList<String>();
    		for(int j = 0 ;j < appraiser_list.size() ; j++ ){
    			JSONObject apprJsonObject = appraiser_list.getJSONObject(j);
    			String dimid = apprJsonObject.getString("dimid");
    			BigDecimal weight = apprJsonObject.getBigDecimal("weight");
    			logger.error("@@@nijb.logger==>###SchemeServerImpl.saveObjectAppraiser weight={}",weight);
    			List<String> staffids = apprJsonObject.getObject("staffids", List.class);
    			if(StringUtils.isEmpty(dimid) || weight == null )
    				throw new AdderBusinessException("参数不能为空", "pm.i18n_core.comm.002");
    			if(staffids != null && staffids.size() > 0){ // 过滤集合中的空字符串和null
					// staffids = staffids.stream().filter(staff_id ->
					// StringUtils.isNotEmpty(staff_id)).collect(Collectors.toList());
					staffids = ListHelper.filter(staffids, null, ListHelper.Operator.ISNOTEmpty, null);
    			}
    			if(staffids == null || staffids.size() <= 0 ){
    				EvaObject evaObject = daoex.load(EvaObject.class, evaobjectid);
    				staffids = evaSettingService.getAppraiserByDim2(dimid,evaObject.getStaffid(),false);
    			}
    			totalweight = totalweight.add(weight);
    			int psn_weight_cnt = 1;
    			for(String staffid : staffids){
    				if(hasExitApprList.contains(staffid))
    					throw new AdderBusinessException("考核人不能重复","pm.i18n_pbc.ps.002");
    				else 
    					hasExitApprList.add(staffid);
    				if(StringUtils.isEmpty(staffid))
    	                throw new AdderBusinessException("考核人不能为空","pm.i18n_pbc.ia.010");
    				EvaSetting appraiser = new EvaSetting();
    				appraiser.setDimid(dimid);
    				// edit by nijb 2021-4-22 支持问题SUPPORT-176826:解决sqlserver批量添加导致decimal精度被不正常四舍五入。
                    appraiser.setWeight(weight.setScale(4));
        			appraiser.setEvaobjectid(evaobjectid);
        			appraiser.setSchemeid(schemeid);
    				appraiser.setId(null);
    				appraiser.setWorkstep(CommonValue.EnumWorkStep.step2.getIndex());
    				appraiser.setStaffid(staffid);
    				appraiser.setTurn(j+1);
    				if(psn_weight_cnt == staffids.size()){
    					appraiser.setPsnweight(calcPsnweight(staffids.size(), true));
    				} else{
    					appraiser.setPsnweight(calcPsnweight(staffids.size(), false));
    				}
    				apprlist.add(appraiser);
    				psn_weight_cnt++;
    			}
    		}
    		if(totalweight.compareTo(new BigDecimal(1)) != 0)
    			throw new AdderBusinessException("考核人权重之和不等于100%。","pm.i18n_pbc.ia.014");
    		daoex.insertBatch(apprlist);
    	}
    	return scheme;
	}
	
	/**
	 * 考核对象上的考核人查询
	 * @param evaobject_ids
	 * @return
	 */
	@Override
	public List<EvaSetting> getObjectAppraiser(List<String> evaobject_ids){
		List<EvaSetting> return_approver_list = new ArrayList<EvaSetting>();
		//查询所选考核对象的所有指标考核人。
		Condition condition1 = new Condition();
		condition1.addExpression("evaobjectid", evaobject_ids, Operator.IN);
		condition1.addExpression("workstep", CommonValue.EnumWorkStep.step2.getIndex());
		List<EvaSetting> approverList = dao.getObjectAppraiser(condition1,new Sorter(Direction.ASC, Arrays.asList("turn","ts")));
		//比较每个考核对象每轮审核人，只要有一轮考核人/类别/权重不同，就是默认为空。（审核人不同就不显示）
		if (approverList.size() > 0) {
			/*
			 * Map<String, Map<String,List<String>>> turnMapAppr = approverList.stream()
			 * .collect(Collectors.groupingBy(ObjectAppraiser -> {return
			 * ObjectAppraiser.getTurn()+"";},
			 * Collectors.groupingBy(EvaSetting::getEvaobjectid,
			 * Collectors.mapping(EvaSetting::getStaffid, Collectors.toList())) ));
			 * 
			 * 
			 * Map<String, Set<String>> dimSet = approverList.stream()
			 * .collect(Collectors.groupingBy(ObjectAppraiser -> {return
			 * ObjectAppraiser.getTurn()+"";}, Collectors.mapping(EvaSetting::getDimid,
			 * Collectors.toSet()) ));
			 * 
			 * Map<String, Set<BigDecimal>> weightSet = approverList.stream()
			 * .collect(Collectors.groupingBy(ObjectAppraiser -> {return
			 * ObjectAppraiser.getTurn()+"";}, Collectors.mapping(EvaSetting::getWeight,
			 * Collectors.toSet()) ));
			 */
			Map<String, Map<String, List<String>>> turnMapAppr = new Hashtable<>();
			Map<String, Set<String>> dimSet = new Hashtable<>();
			Map<String, Set<BigDecimal>> weightSet = new Hashtable<>();
			for (EvaSetting item : approverList) {
				if (!turnMapAppr.containsKey(item.getTurn() + ""))
					turnMapAppr.put(item.getTurn() + "", new Hashtable<String, List<String>>());
				Map<String, List<String>> m = turnMapAppr.get(item.getTurn() + "");
				if (!m.containsKey(item.getEvaobjectid()))
					m.put(item.getEvaobjectid(), new ArrayList<String>());
				m.get(item.getEvaobjectid()).add(item.getStaffid());

				if (!dimSet.containsKey(item.getTurn() + ""))
					dimSet.put(item.getTurn() + "", new HashSet<String>());
				dimSet.get(item.getTurn() + "").add(item.getDimid());

				if (!weightSet.containsKey(item.getTurn() + ""))
					weightSet.put(item.getTurn() + "", new HashSet<BigDecimal>());
				weightSet.get(item.getTurn() + "").add(item.getWeight());
			}
			
			for(int turn = 1 ; turn <= turnMapAppr.size() ; turn++){
				EvaSetting objectAppraiser = new EvaSetting();
				//考核人
				List<PmStaff> filterDuplication = filterDuplication(evaobject_ids, turnMapAppr.get(turn+""));
				objectAppraiser.setOStaffList(filterDuplication);
				objectAppraiser.setTurn(turn);
				//考核人类别
				Set<String> set1 = dimSet.get(turn+"");
				if(set1 != null && set1.size() == 1){
					String dimid = set1.iterator().next();
					objectAppraiser.setDimid(dimid);
					objectAppraiser.setDimname(daoex.load(Dimensionality.class, dimid).getDimname());
				} else {
					objectAppraiser.setDimid("");
					objectAppraiser.setDimname("");
				}
				Set<BigDecimal> set2 = weightSet.get(turn+"");
				if(set2 != null && set2.size() == 1){
					BigDecimal weight = set2.iterator().next();
					objectAppraiser.setWeight(weight);
				} else {
					objectAppraiser.setWeight(null);
				}
				return_approver_list.add(objectAppraiser);
			}
		}
		return return_approver_list;
	}

	/**
	 * 考核对象上的审核人查询
	 * 
	 * @param evaobject_ids
	 * @return
	 */
	@Override
	public List<EvaSetting> getObjectApprover(List<String> evaobject_ids) {
		// 查询所选考核对象的所有指标审核人。
		Condition condition1 = new Condition();
		condition1.addExpression("evaobjectid", evaobject_ids, Operator.IN);
		condition1.addExpression("workstep", CommonValue.EnumWorkStep.step1.getIndex());
		List<EvaSetting> approverList = dao.getObjectAppraiser(condition1,
				new Sorter(Direction.ASC, Arrays.asList("turn", "ts")));
		// 对查询数据进行封装
		// 比较每个考核对象每轮审核人，只要有一轮审核人不同，就是默认为空。（审核人不同就不显示）
		List<EvaSetting> return_approver_list = new ArrayList<EvaSetting>();
		if(approverList.size() > 0){
			// List<String> approver_staffids = approverList.stream().map(EvaSetting ::
			// getStaffid).distinct().collect(Collectors.toList());
			List<String> approver_staffids = ListHelper.collect(approverList, "getStaffid");
			Map<String, PmStaff> approver_staffMap = StaffHelper.queryStaffByIds(approver_staffids);
			
			// Map<String, Map<String,List<String>>> turnMapAppr = approverList.stream()
			// .collect(Collectors.groupingBy(ObjectAppraiser -> {return
			// ObjectAppraiser.getTurn()+"";},
			// Collectors.groupingBy(EvaSetting::getStaffid,
			// Collectors.mapping(EvaSetting::getEvaobjectid, Collectors.toList())) ));
			Map<String, Map<String, List<String>>> turnMapAppr = new Hashtable<>();
			for (EvaSetting item : approverList) {
				if (!turnMapAppr.containsKey(item.getTurn() + ""))
					turnMapAppr.put(item.getTurn() + "", new Hashtable<String, List<String>>());
				Map<String, List<String>> m = turnMapAppr.get(item.getTurn() + "");
				if(StringUtils.isNotEmpty(item.getStaffid())){
					if (!m.containsKey(item.getStaffid()))
						m.put(item.getStaffid(), new ArrayList<String>());
					m.get(item.getStaffid()).add(item.getEvaobjectid());
				}
			}
			
			for (int turn = 1; turn <= turnMapAppr.size(); turn++) {
				EvaSetting objectAppraiser = new EvaSetting();
				return_approver_list.add(objectAppraiser);
				objectAppraiser.setTurn(turn);
				Map<String, List<String>> map = turnMapAppr.get(turn + "");
				if (map == null || map.size() != 1) // 一个轮次只能有一个审核人，多的话就不显示人员
					continue;
				String staffid = map.keySet().iterator().next();
				if (StringUtils.isEmpty(staffid) || map.get(staffid) == null
						|| map.get(staffid).size() != evaobject_ids.size())
					continue;
				objectAppraiser.setStaffid(staffid);
				PmStaff pmStaff = approver_staffMap.get(staffid);
				objectAppraiser.setOStaff(pmStaff);
				objectAppraiser.setStaffname(pmStaff.name);
				// hashMap.put("dimid", appr.getDimid()); // TODO 审核人的类别要不要必存呢？
			}
		}
		return return_approver_list;
	}

	@Override
	public SchemePlan querySchemePlan(String schemeid, Integer step) {
		Condition cond = new Condition();
		cond.addExpression("schemeid", schemeid);
		if (step == null || step == 0)
			step = CommonValue.EnumWorkStep.step2.getIndex();
		cond.addExpression("workstep", step);
		List<SchemePlan> ret = daoex.find(SchemePlan.class, cond, null);
		if (ret.size() > 0)
			return ret.get(0);
		else
			return new SchemePlan();
	}
	
	@Override
	public void saveSchemePlan(SchemePlan plan) {
		if (plan.getSchemeid() == null || plan.getSdate() == null)
			throw new AdderBusinessException("参数不能为空", "pm.i18n_core.comm.002");
		if (plan.getEdate() != null && plan.getEdate().before(plan.getSdate()))
			throw new AdderBusinessException("最后期限要大于开始日期", "pm.i18n_okr.objective.010");	
		if (plan.getWorkstep() == 0)
			plan.setWorkstep(CommonValue.EnumWorkStep.step2.getIndex());
		if (plan.getEdate() != null)
			plan.setEdate(Toolkit.getLastTime(plan.getEdate()));
		SchemePlan oldplan = querySchemePlan(plan.getSchemeid(), plan.getWorkstep());
		if (plan.getId() == null && oldplan.getId() == null) {
			daoex.insert(plan);
		} else {
			oldplan.setSdate(plan.getSdate());
			oldplan.setEdate(plan.getEdate());
			daoex.update(oldplan);
		}
	}
	
    /**
     * 选择了指标审核，要新生成一行记录
     *
     * @param scheme
     * @return
     */
    private List<EvaAppraiser> cloneApprove(Scheme scheme) {
        List<EvaAppraiser> newEvaAppraiser = new ArrayList<EvaAppraiser>();
        for (EvaAppraiser obj : scheme.getOEvaAppraiser()) {
            if (StringUtils.isEmpty(obj.getDimid()))
                throw new AdderBusinessException("方案流程考核人类别不正确", "pm.i18n_core.ps.011");
            // 先删除后增加，所以清空id
            obj.setId(null);
            obj.setSchemeid(scheme.getId());
            obj.setWorkstep(EnumWorkStep.step2.getIndex());
            if(obj.getWeight() != null){
                // edit by nijb 2020-12-15 支持问题项目SUPPORT-99252:解决sqlserver批量添加导致decimal精度被不正常四舍五入。
                obj.setWeight(obj.getWeight().setScale(4));
                logger.error("obj.getWeight={}",obj.getWeight());
            }
            // clone指标审核，结果审核的顺序不调整，显示时可以匹配
            if (obj.getIsapprove()) {
            	// 指标审核的turn可以不从1开始，生成工作流时重新排序
                try {
                    EvaAppraiser newobj = (EvaAppraiser) obj.clone();
                    newobj.setWorkstep(EnumWorkStep.step1.getIndex());
                    newobj.setWeight(null);
                    newEvaAppraiser.add(newobj);
                } catch (CloneNotSupportedException e) {
					throw new AdderBusinessException(e, e.getMessage(), "");
                }
            }
        }
        // 新需求 ： 第二步可不勾选指标审核人
        //if (newEvaAppraiser.isEmpty())
        //    throw new AdderBusinessException("方案流程中没有选择指标审核", "pm.i18n_core.ps.012");
        return newEvaAppraiser;
    }

    /**
     * 保存检查方案数据正确性
     *
     * @param scheme
     */
    private void checkScheme(Scheme scheme) {
		if (StringUtils.isEmpty(scheme.getSchemename()))
			throw new AdderBusinessException("名称不正确", "pm.i18n_core.ps.075");
		checkSchemeSimple(scheme.getId(), scheme.getSchemename(), scheme.getRemark());
		Period p = periodSrv.queryPeriodByID(scheme.getPeriodid());
        if (p == null)
            throw new AdderBusinessException("方案中周期不存在", "pm.i18n_core.ps.015");
        if (StringUtils.isEmpty(scheme.getOrgid()))
            throw new AdderBusinessException("方案所属组织不正确", "pm.i18n_core.ps.016");
        if (!scheme.getPeriodcode().equals(p.getPeriodcode()))
            throw new AdderBusinessException("方案中周期不存在", "pm.i18n_core.ps.015");
        ScoreRule sr = scoreRuleSrv.queryScoreRuleByID(scheme.getScoreruleid());
        if (sr == null)
            throw new AdderBusinessException("方案中评分规则不存在", "pm.i18n_core.ps.017");
        if ( !CommonValue.EnumDataBaseSpecial.Empty.getSymbol().equals(sr.getOrgid()) && !sr.getOrgid().equals(scheme.getOrgid()))
            throw new AdderBusinessException("方案与评分规则所属组织不一致", "pm.i18n_core.ps.018");
        Grade grade = gradeSrv.queryGradeByID(scheme.getGradeid(), true);
        if (grade == null)
            throw new AdderBusinessException("方案中考核结果等级不存在", "pm.i18n_core.ps.019");
        if (!CommonValue.EnumDataBaseSpecial.Empty.getSymbol().equals(grade.getOrgid()) && !grade.getOrgid().equals(scheme.getOrgid()))
            throw new AdderBusinessException("方案与考核等级所属组织不一致", "pm.i18n_core.ps.020");
        boolean ok = true;
        if ((scheme.getSchememode() > CommonValue.EnumSchemeMode.pm_values.getIndex() &&
                scheme.getSchememode() != CommonValue.EnumSchemeMode.pm_mtr.getIndex()) || scheme.getSchememode() < 0)
            ok = false;
        else if (scheme.getAbstentionmode() < 0 || scheme.getAbstentionmode() > 2)
            ok = false;
        else if (scheme.getApplyobj() > 2 || scheme.getApplyobj() < 1)
            ok = false;
        else if (scheme.getScoreway() < 1 || scheme.getScoreway() > 3)
            ok = false;
        if (!ok)
            throw new AdderBusinessException("方案数据不正确", "pm.i18n_core.ps.021");
		if (scheme.isIsdoubleweight() && scheme.getScoreway() != CommonValue.EnumScoreWay.way1.getIndex())
			throw new AdderBusinessException("选择的总分汇总规则不支持按指标分类、指标两级设置权重", "pm.i18n_core.ps.082");
		if (scheme.getOEvaAppraiser() != null) {
            BigDecimal bignum1 = new BigDecimal("100");
            BigDecimal bignum2 = BigDecimal.ZERO;
            for (EvaAppraiser item : scheme.getOEvaAppraiser()) {
                // 循环每一个轮次，检查流程权重合计
                if (item.getTurn() < 0 && item.getTurn() > scheme.getOEvaAppraiser().size())
                    throw new AdderBusinessException("方案流程轮次不正确", "pm.i18n_core.ps.022");
                else if ("".equals(item.getStaffid()))
                    item.setStaffid(null);
                if (item.getWeight() != null)
                    bignum2 = bignum2.add(item.getWeight());
            }
            if (bignum1.compareTo(bignum2) < 0)
                throw new AdderBusinessException("方案数据不正确", "pm.i18n_core.ps.021");
        }
        // 检查考核等级是否涵盖了评分方式
        BigDecimal upper = grade.getOGradeItem().get(0).getUpperlimit();
        BigDecimal lower = grade.getOGradeItem().get(grade.getOGradeItem().size() - 1).getLowerlimit();
        BigDecimal srupper = sr.getUpperlimit();
        BigDecimal srlower = sr.getLowerlimit();
        if (sr.getRuletype() == CommonValue.EnumScoreRuleType.Grade.getIndex()) {
            // 等级式判断标准分范围
            Collections.sort(sr.getOGradeItem(), new Comparator<GradeItem>() {
                @Override
                public int compare(GradeItem o1, GradeItem o2) {
                    int i = o1.getStandardscore().compareTo(o2.getStandardscore());
                    return i;
                }
            });
            srlower = sr.getOGradeItem().get(0).getStandardscore();
            srupper = sr.getOGradeItem().get(sr.getOGradeItem().size() - 1).getStandardscore();
        }
        if (upper != null && upper.compareTo(srupper) < 0 || lower != null && lower.compareTo(srlower) > 0)
            throw new AdderBusinessException("考核等级范围要覆盖评分方式，请修改", "pm.i18n_core.ps.023");
		// 检查考核等级是否为空
		for (GradeItem item : grade.getOGradeItem()) {
			if (item.getArchiveid() == null)
				throw new AdderBusinessException("考核等级规则中缺少等级设置", "pm.i18n_core.ps.066");
		}
    }

	/**
	 * 检查方案数据正确性简单版
	 * 
	 * @param schemeid
	 * @param schemename
	 * @param remark
	 */
	private void checkSchemeSimple(String schemeid, String schemename, String remark) {
		if ("".equals(schemeid))
			throw new AdderBusinessException("方案id不正确", "pm.i18n_core.ps.013");
		if (schemename != null && schemename.trim().length() == 0)
			throw new AdderBusinessException("名称不正确", "pm.i18n_core.ps.075");
		if (schemename != null && schemename.length() > 40)
			throw new AdderBusinessException("方案名称不能超过{0}个字符", "pm.i18n_core.ps.014", "40");
		if (remark != null && remark.length() > 200)
			throw new AdderBusinessException("方案数据不正确", "pm.i18n_core.ps.021");
	}

    /**
     * 检查名称是否重复
     *
     * @param name 方案名称
     * @param id   修改时id
     */
    private void checkNameRepeat(String name, String id) {
        Condition condObj = new Condition();
        condObj.addExpression("schemename", name);
        Pageable page = new PagerRequest(0, 2);
        List<Scheme> objs = daoex.findPage(Scheme.class, condObj, page).getContent();
        if (!objs.isEmpty()) {
            for (Scheme item : objs) {
                if (id == null || !item.getId().equals(id))
                    throw new AdderBusinessException("考核方案名称重复", "pm.i18n_core.ps.024");
            }
        }
    }

	/**
	 * 调整方案流程顺序
	 *
	 * @param scheme
	 *            是否结果审核
	 */
	private void updateSchemeFlow(Scheme scheme) {
		String schemeid = scheme.getId();
		boolean isResultaudited = scheme.isIsresultaudited();
		// 增加结果审核，插入；取消结果审核，删除
		if (isResultaudited) {
			Condition condObj = new Condition();
			condObj.addExpression("schemeid", schemeid);
			Sorter sortObj = new Sorter(Direction.DESC, Arrays.asList("worksteporder"));
			List<SchemeFlow> flows = daoex.find(SchemeFlow.class, condObj, sortObj);
			SchemeFlow flow = new SchemeFlow();
			flow.setSchemeid(schemeid);
			flow.setWorkstep(EnumWorkStep.step3.getIndex());
			flow.setWorksteporder(flows.get(0).getWorksteporder() + 1);
			daoex.insert(flow);
		} else {
			Condition condObj = new Condition();
			condObj.addExpression("schemeid", schemeid);
			condObj.addExpression("workstep", EnumWorkStep.step3.getIndex());
			List<SchemeFlow> flows = daoex.find(SchemeFlow.class, condObj, null);
			for (SchemeFlow item : flows)
				daoex.delete(SchemeFlow.class, item.getId());
		}
	}

	private BigDecimal calcPsnweight(int count, boolean isEnd) {
        BigDecimal decimal = new BigDecimal("1");
        BigDecimal setScale;
        if (isEnd)
            setScale = decimal.divide(new BigDecimal(count), 4,
                    BigDecimal.ROUND_HALF_UP);
        else
            setScale = decimal.divide(new BigDecimal(count), 4,
                    BigDecimal.ROUND_HALF_DOWN);
        return setScale;
    }
	
	/**
	 * 过滤
	 * 
	 * @param evaobject_ids
	 * @param turninfo
	 * @return
	 */
	private List<PmStaff> filterDuplication(List<String> evaobject_ids, Map<String, List<String>> turninfo) {
		// 判断一个轮次，每个考核对象的 考核人是否完全相同
		Boolean hasStaff = true;
		for (int i = 0; i < evaobject_ids.size() - 1; i++) {
			List<String> list1 = turninfo.get(evaobject_ids.get(i));
			List<String> list2 = turninfo.get(evaobject_ids.get(i + 1));
			if (list1 == null || list1.size() == 0 || list2 == null
					|| list2.size() == 0 && list1.size() != list2.size()) {
				hasStaff = false;
				break; // 集合为空，或者个数不一样，代表考核人列表不一样
			}
			list1.removeAll(list2); // 求差集，如果不完全相同 置为false；
			if (list1.size() > 0) {
				hasStaff = false;
				break;
			}
		}
		if (hasStaff) {
			List<String> staffidslist = turninfo.get(evaobject_ids.get(evaobject_ids.size() - 1));
			Map<String, PmStaff> approver_staffMap = StaffHelper.queryStaffByIds(staffidslist);
			// return approver_staffMap.values().stream().sorted((staff1, staff2) ->
			// staff1.id.compareTo(staff2.id)).collect(Collectors.toList());
			List<PmStaff> staffList = new ArrayList<>(approver_staffMap.values());
			ListHelper.sorted(staffList, "id");
			return staffList;
		} else {
			return new ArrayList<PmStaff>();
		}
	}

	/**
	 * 判断是否是价值观方案
	 * 
	 * @param scheme
	 */
	private void checkSchemeValues(Scheme scheme) {
		if (!StringUtils.isEmpty(scheme.getTagid())) {
			String tagcode = tagSrv.queryTagCodeById(scheme.getTagid());
			if ("302".equals(tagcode)) {
				scheme.setSchememode(CommonValue.EnumSchemeMode.pm_values.getIndex());
				scheme.setIsallowfillup(false);
				scheme.setIndisource(CommonValue.EnumIndiSource.hrfill.getIndex());
			}
		}
	}

	/**
	 * 保存默认流程
	 * 
	 * @param scheme
	 */
	private void saveSchemeFlow(Scheme scheme) {
		// 对步骤枚举进行排序
		List<String> stepList = new ArrayList<>();
		for (EnumWorkStep item : CommonValue.EnumWorkStep.values()) {
			stepList.add(String.valueOf(item.getIndex()));
		}
		Collections.sort(stepList);

		if (!scheme.isIsresultaudited()) {
			// 没有结果审核环节
			stepList.remove(String.valueOf(CommonValue.EnumWorkStep.step3.getIndex()));
		}
		if (!scheme.isIsallowfillup()) {
			// 不允许员工填报时，HR填写则跳过指标审核，指标下达需要加流程
			if (scheme.getIndisource() == CommonValue.EnumIndiSource.hrfill.getIndex()) {
				stepList.remove(String.valueOf(CommonValue.EnumWorkStep.step1.getIndex()));
				stepList.remove(String.valueOf(CommonValue.EnumWorkStep.step4.getIndex()));
			} else if (scheme.getIndisource() == CommonValue.EnumIndiSource.issued.getIndex()) {
				stepList.remove(String.valueOf(CommonValue.EnumWorkStep.step1.getIndex()));
			}
		} else {
			stepList.remove(String.valueOf(CommonValue.EnumWorkStep.step4.getIndex()));
		}
		List<SchemeFlow> flows = new ArrayList<>();
		int iOrder = 1;
		for (int i = 0; i < stepList.size(); i++) {
			SchemeFlow flow = new SchemeFlow();
			flow.setSchemeid(scheme.getId());
			flow.setWorkstep(Integer.parseInt(stepList.get(i)));
			flow.setWorksteporder(iOrder);
			flows.add(flow);
			iOrder++;
		}
		daoex.insertBatch(flows);
	}
	
	private void saveSchemeFlowOld(Scheme scheme) {
		// 旧的保存默认流程
		List<SchemeFlow> flows = new ArrayList<SchemeFlow>();
		int iStepCount = 3;// 总环节个数
		int iStepStart = 1;// 开始环节序号
		if (!scheme.isIsresultaudited())
			iStepCount--;
		if (!scheme.isIsallowfillup() && scheme.getIndisource() == CommonValue.EnumIndiSource.hrfill.getIndex())
			iStepStart++;
		int iOrder = 1;
		for (int i = iStepStart; i <= iStepCount; i++) {
			SchemeFlow flow = new SchemeFlow();
			flow.setSchemeid(scheme.getId());
			flow.setWorkstep(i * 10);
			flow.setWorksteporder(iOrder);
			flows.add(flow);
			iOrder++;
		}
        daoex.insertBatch(flows);
	}
	
	/**
	 * 根据人查询方案
	 * 
	 * @param staffids
	 */
	@Override
	public List<String> querySchemesByStaffs(List<String> staffids) {
		// 员工绩效下确认方案参照
		List<String> scmlst = dao.querySchemesByStaffs(staffids);
		return scmlst;
	}
	
	 @Override
    public void exportTemplateBySchemeId(HttpServletRequest request, HttpServletResponse response, Scheme scheme) {
        String schemeid = scheme.getId();
        String grades=scheme.getGradeid();
        //获取考核等级
        List<GradeItem> gradeItemsss=iExclQueryService.getGradeByID(grades);
        List<String> listschemeid=new ArrayList();
        listschemeid.add(schemeid);
        //根据方案-查询所有考核对象
        List<EvaObject> evaObjectList = queryEvaObjPageBySchemeList(listschemeid);
        List<String> staffidList = ListHelper.collect(evaObjectList, "getStaffid");
        List<PmStaff> pmStaffList = StaffHelper.queryStaffByIds3(staffidList);
        List<Map<String,String>> dataList = new ArrayList<>();
        Collections.sort(pmStaffList);
        for (PmStaff pmStaff : pmStaffList) {
            Map<String,String> data = new HashMap<>();
            data.put("staffcode",pmStaff.code == null ? "" : pmStaff.code);
            data.put("staffname",pmStaff.name);
            data.put("orgname",pmStaff.corpname == null ? "" : pmStaff.corpname);
            data.put("deptname",pmStaff.deptname == null ? "" : pmStaff.deptname);
            dataList.add(data);
        }
        iExclQueryService.exportTemplateByScheme2Excel(request,response,dataList,scheme.getSchemename(),gradeItemsss);
    }

    /**
     * @author ZhangTao
     * @description 根据方案查询对应的考核对象
     * @date 2019/6/20
     * @param schemeidList
     * @return java.util.List<com.yonyou.hrcloud.pm.ps.model.EvaObject>
     **/
    private List<EvaObject> queryEvaObjPageBySchemeList(List<String> schemeidList){
        Condition evaObjCondition = new Condition();
        evaObjCondition.addExpression("schemeid",schemeidList,Operator.IN);
        Sorter evaObjSort = new Sorter(Direction.ASC,"groupid");
        List<EvaObject> evaObjList = daoex.find(EvaObject.class,evaObjCondition,evaObjSort);
        return evaObjList;
    }
}
