package nc.impl.trn.regmng;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.naming.NamingException;

import nc.bs.framework.common.NCLocator;
import nc.bs.logging.Logger;
import nc.bs.pub.SystemException;
import nc.bs.pub.filesystem.IFileSystemService;
import nc.bs.pub.pflock.PfBusinessLock;
import nc.bs.pub.pflock.VOConsistenceCheck;
import nc.bs.pub.pflock.VOLockData;
import nc.bs.pub.pflock.VOsConsistenceCheck;
import nc.bs.pub.pflock.VOsLockData;
import nc.bs.sec.esapi.NCESAPI;
import nc.bs.uif2.VersionConflictException;
import nc.bs.uif2.validation.DefaultValidationService;
import nc.hr.frame.persistence.SimpleDocServiceTemplate;
import nc.hr.utils.BillCodeHelper;
import nc.hr.utils.InSQLCreator;
import nc.hr.utils.PubEnv;
import nc.hr.utils.ResHelper;
import nc.hr.utils.SQLHelper;
import nc.hr.utils.StringPiecer;
import nc.itf.hi.IPersonRecordService;
import nc.itf.hr.frame.IHrBillCode;
import nc.itf.hr.frame.IPersistenceRetrieve;
import nc.itf.hr.frame.IPersistenceUpdate;
import nc.itf.hr.message.IHRMessageSend;
import nc.itf.hr.pf.IHrPf;
import nc.itf.hrp.psnbudget.IOrgBudgetQueryService;
import nc.itf.om.IAOSQueryService;
import nc.itf.trn.IItemSetAdapter;
import nc.itf.trn.TrnDelegator;
import nc.itf.trn.regmng.IRegmngManageService;
import nc.itf.trn.regmng.IRegmngQueryService;
import nc.itf.uap.busibean.SysinitAccessor;
import nc.itf.uap.pf.IplatFormEntry;
import nc.itf.uap.pf.metadata.IFlowBizItf;
import nc.md.data.access.NCObject;
import nc.md.model.IBean;
import nc.md.model.impl.MDEnum;
import nc.message.util.IDefaultMsgConst;
import nc.message.util.MessageCenter;
import nc.message.vo.MessageVO;
import nc.message.vo.NCMessage;
import nc.pub.billcode.itf.IBillcodeManage;
import nc.pub.billcode.itf.IBillcodeRuleQryService;
import nc.pub.billcode.vo.BillCodeContext;
import nc.pub.billcode.vo.BillCodeElemVO;
import nc.pub.billcode.vo.BillCodeRuleVO;
import nc.pub.tools.HiCacheUtils;
import nc.pub.tools.VOUtils;
import nc.pubitf.para.SysInitQuery;
import nc.vo.bd.defdoc.DefdocVO;
import nc.vo.bd.psn.PsnClVO;
import nc.vo.hi.entrymng.HiSendMsgHelper;
import nc.vo.hi.psndoc.PsnJobVO;
import nc.vo.hi.psndoc.PsndocVO;
import nc.vo.hi.psndoc.TrialVO;
import nc.vo.hi.psndoc.enumeration.TrnseventEnum;
import nc.vo.hi.pub.BillCodeRepeatBusinessException;
import nc.vo.hi.pub.HICommonValue;
import nc.vo.hr.message.HRBusiMessageVO;
import nc.vo.hr.tools.pub.HRConstEnum;
import nc.vo.hrp.psnorgbudget.ValidateResultVO;
import nc.vo.om.job.JobVO;
import nc.vo.om.post.PostVO;
import nc.vo.org.DeptVO;
import nc.vo.org.OrgVO;
import nc.vo.pf.change.IActionDriveChecker;
import nc.vo.pf.change.PfUtilBaseTools;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.BusinessException;
import nc.vo.pub.SuperVO;
import nc.vo.pub.VOStatus;
import nc.vo.pub.ValidationException;
import nc.vo.pub.filesystem.NCFileNode;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDateTime;
import nc.vo.pub.lang.UFLiteralDate;
import nc.vo.pub.pf.IPfRetCheckInfo;
import nc.vo.pub.workflownote.WorkflownoteVO;
import nc.vo.trn.pub.BeanUtil;
import nc.vo.trn.pub.TRNConst;
import nc.vo.trn.pub.TrnManageService;
import nc.vo.trn.regitem.TrnRegItemVO;
import nc.vo.trn.regmng.AggRegapplyVO;
import nc.vo.trn.regmng.Glbdef2VO;
import nc.vo.trn.regmng.RegapplyVO;
import nc.vo.uap.pf.PFBatchExceptionInfo;
import nc.vo.uap.pf.PfProcessBatchRetObject;
import nc.vo.uap.rbac.constant.INCSystemUserConst;
import nc.vo.uif2.LoginContext;
import nc.vo.wfengine.definition.WorkflowTypeEnum;
import nccloud.commons.collections.MapUtils;
import nccloud.commons.lang.ArrayUtils;
import nccloud.commons.lang.StringUtils;
import nccloud.framework.service.ServiceLocator;
import nccloud.itf.hrsscpub.utils.BusiActionConst;
import nccloud.itf.hrsscpub.utils.SatisfactSurveryUtil;
import nccloud.itf.hrsscpub.utils.WorkLoadCountUtil;
import nccloud.pubitf.riart.pflow.CloudPFlowContext;
import nccloud.pubitf.riart.pflow.ICloudScriptPFlowService;

public class RegmngManageServiceImpl extends TrnManageService implements IRegmngManageService, IRegmngQueryService, IActionDriveChecker {
 
	private final String DOC_NAME = "RegmngManage";

	private SimpleDocServiceTemplate serviceTemplate;

	public PfProcessBatchRetObject batchCommitBill(AggregatedValueObject[] bills) throws BusinessException {

		PFBatchExceptionInfo exInfo = new PFBatchExceptionInfo();
		ArrayList<AggregatedValueObject> successObj = new ArrayList<AggregatedValueObject>();
		for (int i = 0; i < bills.length; i++) {
			try {
				AggregatedValueObject aggVO = NCLocator.getInstance().lookup(IRegmngManageService.class).commitBill_RequiresNew(bills[i]);
				successObj.add(aggVO);
			} catch (Exception e) {
				if (e instanceof VersionConflictException) {
					exInfo.putErrorMessage(i, bills[i], ((VersionConflictException) e).getBusiObject() == null ? ""
							: ((VersionConflictException) e).getBusiObject().toString());
				} else {
					exInfo.putErrorMessage(i, bills[i], StringUtils.isBlank(e.getMessage()) ? "" : e.getMessage());
				}
				Logger.error(e.getMessage(), e);
			}
		}
		return new PfProcessBatchRetObject(successObj.toArray(new AggregatedValueObject[0]), exInfo);
	}

	/**
	 * 批量保存入职申请单
	 *
	 * @param aggvo
	 * @param pkPsnjobs
	 * @param context
	 * @return AggRegapplyVO[]
	 * @throws BusinessException
	 */
	public AggRegapplyVO[] batchSaveBill(AggRegapplyVO aggvo, ArrayList<String> pkPsnjobs, LoginContext context, String[] billCodes)
			throws BusinessException {
		if (null == pkPsnjobs || pkPsnjobs.isEmpty()) {
			return null;
		}
		// 优化效率，将所有的人员工作记录通过一个查询出来，而不是在循环里面循环查询
		HashMap<String, PsnJobVO> mapjobs = getQueryJobs(pkPsnjobs);
		HashMap<String, TrialVO> maptrials = getQueryOrgs(pkPsnjobs);

		boolean isAutoGenerateBillCode = isAutoGenerateBillCode(TRNConst.BillTYPE_REG, context.getPk_group(), context.getPk_org());
		ArrayList<AggRegapplyVO> al = new ArrayList<AggRegapplyVO>();
		if (!isAutoGenerateBillCode) {
			// 如果不自动生成编码,则对编码规则进行加锁
			BillCodeHelper.lockBillCodeRule("hr_auto_billcode" + TRNConst.BillTYPE_REG, 100);
		}
		try {
			String prefix = "ZD" + TRNConst.BillTYPE_REG + PubEnv.getServerDate().toStdString();
			// 不自动生成单据号 /默认规则生成 "单据类型+yyyy-mm-dd+_流水号"
			String flowCode = SQLHelper.getFlowCode(prefix, RegapplyVO.BILL_CODE, RegapplyVO.class);
			for (int i = 0; i < pkPsnjobs.size(); i++) {
				AggRegapplyVO temp = clone(aggvo);
				RegapplyVO head = (RegapplyVO) temp.getParentVO();
				if (isAutoGenerateBillCode && billCodes != null && billCodes.length > 0 && billCodes[i] != null) {
					head.setBill_code(billCodes[i]);
				} else {
					// 不自动生成单据号
					head.setBill_code(prefix + "_" + getFlowCode(flowCode, i));
				}
				head.setApprove_state(IPfRetCheckInfo.NOSTATE);
				head.setBillmaker(context.getPk_loginUser());
				// head.setApply_date(PubEnv.getServerLiteralDate());
				head.setPk_billtype(TRNConst.BillTYPE_REG);
				head.setPk_org(context.getPk_org());
				head.setPk_group(context.getPk_group());

				// PsnJobVO oldJobVO = queryByPk(PsnJobVO.class, pkPsnjobs.get(i), true);
				PsnJobVO oldJobVO = mapjobs.get(pkPsnjobs.get(i));
				if (null == oldJobVO) {
					continue;
				}
				head.setPk_psnjob(oldJobVO.getPk_psnjob());
				head.setPk_psndoc(oldJobVO.getPk_psndoc());
				head.setPk_psnorg(oldJobVO.getPk_psnorg());
				head.setAssgid(oldJobVO.getAssgid());
				// 设置转正前信息
				for (String attr : oldJobVO.getAttributeNames()) {
					head.setAttributeValue("old" + attr, oldJobVO.getAttributeValue(attr));
				}

				// 设置转正后信息
				// 岗位/职务信息特殊处理
				String[] flds =
						{
								RegapplyVO.NEWPK_POST,
								RegapplyVO.NEWPK_POSTSERIES,
								RegapplyVO.NEWPK_JOB,
								RegapplyVO.NEWPK_JOBGRADE,
								RegapplyVO.NEWPK_JOBRANK,
								RegapplyVO.NEWSERIES};

				TrnRegItemVO[] itemvos =
						TrnDelegator.getIItemSetQueryService().queryItemSetByOrg(TRNConst.REGITEM_BEANID, context.getPk_group(),
								context.getPk_org(), head.getProbation_type());

				for (int j = 0; itemvos != null && j < itemvos.length; j++) {
					if (itemvos[j].getItemkey().startsWith("old") || ArrayUtils.contains(flds, itemvos[j].getItemkey())) {
						// 转正前项目或是岗位职务相关项目不处理
						continue;
					}
					if (itemvos[j] != null && itemvos[j].getIsdefault() != null && itemvos[j].getIsdefault().booleanValue()
							&& head.getAttributeValue(itemvos[j].getItemkey()) == null) {
						head.setAttributeValue(itemvos[j].getItemkey(), oldJobVO.getAttributeValue(itemvos[j].getItemkey().substring(3)));
					}
				}

				// 处理岗位职务信息
				// 默认项目中没有职务,则职务为空,那么职务相关的就都为空
				String newPost = head.getNewpk_post();
				String newJob = head.getNewpk_job();

				if (newPost != null && newJob != null) {
					// 岗位职务都有,不操作
				} else if (newPost != null && newJob == null) {
					// 有岗位没职务,不操作
					// 此处只考虑职等的默认情况
					TrnRegItemVO rankItem = getItemByItemkey(itemvos, RegapplyVO.NEWPK_JOBRANK);
					if (rankItem != null && rankItem.getIsdefault() != null && rankItem.getIsdefault().booleanValue()
							&& head.getNewpk_jobrank() == null) {
						head.setNewpk_jobrank(head.getOldpk_jobrank());
					}
				} else if (newPost == null && newJob != null) {
					// 没岗位有职务,不操作
				} else {
					// 没岗位没职务考虑默认的情况
					// 只有在前后部门相同的情况下才能处理岗位相关信息,否则岗位不赋值
					if (head.getOldpk_dept().equals(head.getNewpk_dept())) {
						TrnRegItemVO postItem = getItemByItemkey(itemvos, RegapplyVO.NEWPK_POST);
						TrnRegItemVO jobItem = getItemByItemkey(itemvos, RegapplyVO.NEWPK_JOB);
						if (postItem != null && postItem.getIsdefault() != null && postItem.getIsdefault().booleanValue()) {
							// 如果岗位默认,则岗位职务都按照前项目设置
							head.setNewpk_post(head.getOldpk_post());
							head.setNewpk_postseries(head.getOldpk_postseries());
							head.setNewpk_job(head.getOldpk_job());
							head.setNewpk_jobrank(head.getOldpk_jobrank());
							head.setNewpk_jobgrade(head.getOldpk_jobgrade());
							head.setNewseries(head.getOldseries());
						} else if (jobItem != null && jobItem.getIsdefault() != null && jobItem.getIsdefault().booleanValue()) {
							// 岗位没有默认,职务相关的按照前项目设置
							head.setNewpk_job(head.getOldpk_job());
							head.setNewpk_jobrank(head.getOldpk_jobrank());
							head.setNewpk_jobgrade(head.getOldpk_jobgrade());
							head.setNewseries(head.getOldseries());
						}
					}
				}

				// 试用信息处理
				if (MapUtils.isNotEmpty(maptrials)) {
					TrialVO trialVO = maptrials.get(pkPsnjobs.get(i));
					if (null != trialVO) {
						head.setBegin_date(trialVO.getBegindate());
						head.setEnd_date(trialVO.getEnddate());
					}
				}

				// String where = " pk_psnorg = '" + oldJobVO.getPk_psnorg() + "' and endflag = 'N' ";
				// TrialVO[] trialVOs = (TrialVO[]) getIPersistenceRetrieve().retrieveByClause(null,
				// TrialVO.class, where);
				// if (trialVOs != null && trialVOs.length > 0)
				// {
				// head.setBegin_date(trialVOs[0].getBegindate());
				// head.setEnd_date(trialVOs[0].getEnddate());
				// }

				al.add(temp);
			}

			checkBillCodeRepeat(al.toArray(new AggRegapplyVO[0]));
			AggRegapplyVO[] resultAggVOs = saveBatchBill(al.toArray(new AggRegapplyVO[0]));
			//add by@chenzf 批量添加子表信息 2021-10-11 18:58:15 begin
			if(resultAggVOs != null && resultAggVOs.length > 0) {
				DefdocVO[] defdocVOs = (DefdocVO[]) ServiceLocator.find(IPersistenceRetrieve.class).retrieveByClause(null, DefdocVO.class, "pk_defdoclist = (select pk_defdoclist from bd_defdoclist where code = 'HRTRN099' and nvl(dr,0) = 0) and nvl(dr,0) = 0");
				List<Glbdef2VO> glbdef1List = new ArrayList();
				for(AggRegapplyVO agg :resultAggVOs) {
					List<Glbdef2VO> bvoList = new ArrayList();
					if(defdocVOs != null && defdocVOs.length > 0) {
						for(DefdocVO vo : defdocVOs) {
							Glbdef2VO glbdef1VO = new Glbdef2VO();
							glbdef1VO.setAttributeValue("glbdef1", vo.getPk_defdoc());
							glbdef1VO.setAttributeValue("glbdef2", vo.getDef1());
							glbdef1VO.setAttributeValue("glbdef3", vo.getDef2());
							glbdef1VO.setAttributeValue("glbdef4", vo.getDef3());
							glbdef1VO.setAttributeValue("glbdef5", vo.getDef4());
							glbdef1VO.setPk_hi_regapply(agg.getParentVO().getPrimaryKey());
							glbdef1VO.setStatus(VOStatus.NEW);
							bvoList.add(glbdef1VO);
							glbdef1List.add(glbdef1VO);
						}
						agg.setChildrenVO(bvoList.toArray(new Glbdef2VO[0]));
					}
				}
				if(glbdef1List.size() > 0) {
					String[] pks = getMDPersistenceService().saveBill(glbdef1List.toArray(new Glbdef2VO[0]));
				}
			}
			//add by@chenzf 批量添加子表信息 2021-10-11 18:58:15 end
			return resultAggVOs;
		} catch (Exception e) {
			Logger.error(e.getMessage(), e);
			throw new BusinessException(e.getMessage());
		} finally {
			if (!isAutoGenerateBillCode) {
				// 如果不自动生成编码,则对编码规则进行加锁
				BillCodeHelper.unlockBillCodeRule("hr_auto_billcode" + TRNConst.BillTYPE_REG);
			}
		}
	}

	// 根据工作记录主键查询对应的工作记录
	public HashMap<String, PsnJobVO> getQueryJobs(ArrayList<String> pkPsnjobs) throws BusinessException {
		HashMap<String, PsnJobVO> mapjob = new HashMap<String, PsnJobVO>();
		PsnJobVO[] psnjobvo = queryByPks(PsnJobVO.class, pkPsnjobs.toArray(new String[0]));
		if (!ArrayUtils.isEmpty(psnjobvo)) {
			for (int i = 0; i < pkPsnjobs.size(); i++) {
				String pk_psnjob = pkPsnjobs.get(i);
				for (int j = 0; j < psnjobvo.length; j++) {
					if (StringUtils.isNotBlank(pk_psnjob) && pk_psnjob.equals(psnjobvo[j].getPk_psnjob())) {
						mapjob.put(pk_psnjob, psnjobvo[j]);
					}
				}
			}
		}
		return mapjob;
	}

	// 根据工作记录主键查询对应的组织关系--试用信息
	public HashMap<String, TrialVO> getQueryOrgs(ArrayList<String> pkPsnjobs) throws BusinessException {
		HashMap<String, TrialVO> mapjob = new HashMap<String, TrialVO>();
		PsnJobVO[] psnjobvo = queryByPks(PsnJobVO.class, pkPsnjobs.toArray(new String[0]));
		if (!ArrayUtils.isEmpty(psnjobvo)) {
			String[] pk_psnorgs = StringPiecer.getStrArrayDistinct(psnjobvo, PsnJobVO.PK_PSNORG);
			InSQLCreator insql = new InSQLCreator();
			String cond = " pk_psnorg in (" + insql.getInSQL(pk_psnorgs) + ") and endflag = 'N' ";
			TrialVO[] trialvo =
					(TrialVO[]) NCLocator.getInstance().lookup(IPersistenceRetrieve.class).retrieveByClause(null, TrialVO.class, cond);
			if (!ArrayUtils.isEmpty(trialvo)) {
				for (int i = 0; i < pkPsnjobs.size(); i++) {
					String pk_psnjob = pkPsnjobs.get(i);
					for (int j = 0; j < trialvo.length; j++) {
						if (StringUtils.isNotBlank(pk_psnjob) && pk_psnjob.equals(trialvo[j].getPk_psnjob())) {
							mapjob.put(pk_psnjob, trialvo[j]);
						}
					}
				}
			}
		}
		return mapjob;
	}

	/**
	 * 插入一条审批意见
	 *
	 * @param itf
	 * @param strApproveId
	 * @param strCheckNote
	 * @param blPassed
	 * @param billtype
	 * @return WorkflownoteVO
	 * @throws BusinessException
	 */
	private WorkflownoteVO buildWorkflownoteVO(IFlowBizItf itf, String strApproveId, String strCheckNote, int blPassed, String billtype)
			throws BusinessException {

		WorkflownoteVO worknoteVO = new WorkflownoteVO();
		worknoteVO.setBillid(itf.getBillId());// 单据ID
		worknoteVO.setBillVersionPK(itf.getBillId());
		worknoteVO.setChecknote(strCheckNote);// 审批意见
		// 发送日期
		worknoteVO.setSenddate(PubEnv.getServerTime());
		worknoteVO.setDealdate(PubEnv.getServerTime());// 审批日期
		// 组织
		worknoteVO.setPk_org(itf.getPkorg());
		// 单据编号
		worknoteVO.setBillno(itf.getBillNo());
		// 发送人
		String sendman = itf.getApprover() == null ? itf.getBillMaker() : itf.getApprover();
		worknoteVO.setSenderman(sendman);
		// Y,审批通过，N，审批不通过
		worknoteVO.setApproveresult(IPfRetCheckInfo.NOSTATE == blPassed ? "R" : IPfRetCheckInfo.PASSING == blPassed ? "Y" : "N");
		worknoteVO.setApprovestatus(1);// 直批的状态
		worknoteVO.setIscheck(IPfRetCheckInfo.PASSING == blPassed ? "Y" : IPfRetCheckInfo.NOPASS == blPassed ? "N" : "X");
		worknoteVO.setActiontype("APPROVE");
		worknoteVO.setCheckman(strApproveId);
		// 单据类型
		worknoteVO.setPk_billtype(billtype);
		worknoteVO.setWorkflow_type(WorkflowTypeEnum.Approveflow.getIntValue());
		return worknoteVO;
	}

	/**
	 * 回写入职表的审批信息
	 *
	 * @param itf
	 * @param strApproveId
	 * @param strApproveDate
	 * @param strCheckNote
	 * @param intAppState
	 * @throws BusinessException
	 */
	private void changeBillData(IFlowBizItf itf, String strApproveId, UFDateTime strApproveDate, String strCheckNote, Integer intAppState)
			throws BusinessException {

		if (itf == null) {
			return;
		}
		itf.setApprover(strApproveId);
		itf.setApproveNote(strCheckNote);
		itf.setApproveDate(strApproveDate);
		itf.setApproveStatus(intAppState);
	}

	/**
	 * 检查重号
	 *
	 * @param <T>
	 * @param billvos
	 */
	private <T extends AggregatedValueObject> void checkBillCodeRepeat(T... billvos) throws BusinessException {
		StringBuffer errMsg = new StringBuffer();
		ArrayList<String> repeatCodes = new ArrayList<String>();
		IPersistenceRetrieve ser = NCLocator.getInstance().lookup(IPersistenceRetrieve.class);
		for (T vo : billvos) {
			IFlowBizItf itf = NCObject.newInstance(vo).getBizInterface(IFlowBizItf.class);
			String billCode = itf.getBillNo();
			String pk_regapply = itf.getBillId();
			String billType = itf.getBilltype();
			String whereSql =
					RegapplyVO.BILL_CODE + " = '" + NCESAPI.sqlEncode(billCode) + "' and pk_group = '" + PubEnv.getPk_group() + "'  and "
							+ RegapplyVO.PK_BILLTYPE + " = '" + billType + "'";
			if (!StringUtils.isEmpty(pk_regapply)) {
				whereSql += " and " + RegapplyVO.PK_HI_REGAPPLY + " <> '" + pk_regapply + "'";
			}
			int count = ser.getCountByCondition(RegapplyVO.getDefaultTableName(), whereSql);
			if (count > 0) {
				errMsg.append('\n' + ResHelper.getString("6007entry", "06007entry0050")/* @res "单据[" */ + billCode
						+ ResHelper.getString("6007entry", "06007entry0051")/* @res "]的单据号已存在" */);
				repeatCodes.add(billCode);
				continue;
			}
		}
		if (errMsg.length() > 0) {
			BillCodeRepeatBusinessException ex = new BillCodeRepeatBusinessException(ResHelper.getString("6007entry", "06007entry0052")/*
			 * @
			 * res
			 * "保存失败,具体原因如下:"
			 */
					+ errMsg.toString());
			ex.setRepeatCodes(repeatCodes.toArray(new String[0]));
			throw ex;
		}
	}

	/**
	 * 复制一个聚合VO
	 */
	private AggRegapplyVO clone(AggRegapplyVO src) {

		AggRegapplyVO trg = new AggRegapplyVO();
		RegapplyVO head = new RegapplyVO();
		trg.setParentVO(head);
		for (String attrName : src.getParentVO().getAttributeNames()) {
			trg.getParentVO().setAttributeValue(attrName, src.getParentVO().getAttributeValue(attrName));
		}
		return trg;
	}

	public AggregatedValueObject commitBill_RequiresNew(AggregatedValueObject aggvo) throws BusinessException {
		RegapplyVO billvo = (RegapplyVO) ((AggRegapplyVO) aggvo).getParentVO();
		// 使用试用结果校验
		if (billvo.getTrialresult() == null) {
			throw new BusinessException(ResHelper.getString("6009reg", "06009reg0030")/* @res "单据未填写试用结果" */);
		}
		// 必输项校验
		String errMsg = getMsg(billvo);
		if (StringUtils.isNotBlank(errMsg)) {
			throw new BusinessException(ResHelper.getString("6009reg", "06009reg0031")/* @res "单据中存在未填写的必输项" */);
		}

		if (!isHasFile(billvo)) {
			throw new BusinessException(ResHelper.getString("6009reg", "06009reg0047")/* @res "单据没有上传附件" */);
		}

		String billmaker = (String) aggvo.getParentVO().getAttributeValue(RegapplyVO.BILLMAKER);
		if (billmaker != null && INCSystemUserConst.NC_USER_PK.equals(billmaker)) {
			aggvo.getParentVO().setAttributeValue(RegapplyVO.BILLMAKER, PubEnv.getPk_user());
		}
		return getIHrPf().commitBill_RequiresNew(aggvo);
	}

	private PsnJobVO createNewPsnjob(RegapplyVO bill) throws BusinessException {

		// 给转正项目对应的字段赋值如果单据中有值则使用单据中的值否则使用上一条记录的值
		// 得到上一条记录
		PsnJobVO[] lastvo = getLastVO(PsnJobVO.class, bill.getPk_psnorg(), 1);
		if (lastvo == null || lastvo.length == 0) {
			throw new BusinessException("此人最新任职记录为空，请检查最新任职信息！");
		}

		PsnJobVO psnjob = new PsnJobVO();
		// 新任职开始日期 = 转正日期
		if (bill.getRegulardate() != null) {
			psnjob.setBegindate(bill.getRegulardate());
		} else {
			psnjob.setBegindate(PubEnv.getServerLiteralDate());
		}
		psnjob.setEnddate(null);
		psnjob.setEndflag(UFBoolean.FALSE);
		psnjob.setIsmainjob(UFBoolean.TRUE);
		psnjob.setLastflag(UFBoolean.TRUE);
		psnjob.setPk_hrgroup(bill.getPk_group());
		psnjob.setPk_group(bill.getPk_group());
		psnjob.setPk_hrorg(bill.getPk_org());
		psnjob.setPk_psndoc(bill.getPk_psndoc());
		psnjob.setPk_psnorg(bill.getPk_psnorg());
		psnjob.setPk_psnjob(null);
		psnjob.setPsntype(0);
		psnjob.setAssgid(1);
		// 转正后默认为
		psnjob.setPoststat(UFBoolean.TRUE);
		// 试用信息
		psnjob.setTrial_type(null);
		psnjob.setRecordnum(0);
		psnjob.setTrnsevent((Integer) ((MDEnum) TrnseventEnum.REGAPPLY).value());
		psnjob.setTrnstype(TRNConst.TRANSTYPE_REG);
		psnjob.setTrial_flag(UFBoolean.FALSE);
		psnjob.setShoworder(9999999);
		// 单据信息
		psnjob.setOribilltype(TRNConst.BillTYPE_REG);
		psnjob.setOribillpk(bill.getPk_hi_regapply());
		// 员工号要使用上一条的员工号
		psnjob.setClerkcode(lastvo[0].getClerkcode());

		for (String name : bill.getAttributeNames()) {
			// 岗位、职务等信息不用前一条的数据
			if (name.startsWith("new")) {
				Object value = bill.getAttributeValue(name);
				psnjob.setAttributeValue(name.substring(3), value);
			}
		}

		UFBoolean blPoststate = UFBoolean.FALSE;

		// 是否在岗 在调配申请时要特殊处理
		TrnRegItemVO[] tempvos =
				TrnDelegator.getIItemSetQueryService().queryItemSetByOrg(TRNConst.REGITEM_BEANID, bill.getPk_group(), bill.getPk_org(),
						bill.getProbation_type());
		TrnRegItemVO vo = null;
		for (int i = 0; tempvos != null && i < tempvos.length; i++) {
			if (!"newpoststat".equals(tempvos[i].getItemkey())) {
				continue;
			}
			vo = tempvos[i];
		}
		if (vo == null) {
			// 调配项目中，没有是否在岗，使用上一条的信息
			blPoststate = lastvo[0].getPoststat();
		} else {
			if (vo.getIsedit() != null && vo.getIsedit().booleanValue()) {
				// 调配项目中用,并且可以调整,使用单据中的
				blPoststate = bill.getNewpoststat();
			} else {
				// 不能调整 使用工作记录中的
				blPoststate = lastvo[0].getPoststat();
			}
		}

		psnjob.setPoststat(blPoststate);

		return psnjob;
	}

	@Override
	public Hashtable<String, String[]> createUserValue(AggregatedValueObject[] aggvos) throws BusinessException {

		RegapplyVO[] vos = new RegapplyVO[aggvos.length];
		for (int i = 0; aggvos != null && i < aggvos.length; i++) {
			vos[i] = (RegapplyVO) aggvos[i].getParentVO();
		}
		return createValueFromBills(vos);
	}

	private Hashtable<String, String[]> createValueFromBills(RegapplyVO[] vos) throws BusinessException {

		String[] fieldCode = TRNConst.FIELDCODE_REG;
		Hashtable<String, String[]> hm = new Hashtable<String, String[]>();
		for (int i = 0; vos != null && i < vos.length; i++) {
			RegapplyVO bill = vos[i];
			for (int j = 0; j < fieldCode.length; j++) {
				String value = "";
				if (RegapplyVO.BILL_CODE.equals(fieldCode[j])) {
					// 单据编码
					value = bill.getBill_code();
				} else if (RegapplyVO.REGULARDATE.equals(fieldCode[j])) {
					// 转正日期
					value = bill.getRegulardate() == null ? "" : bill.getRegulardate().toStdString();
				} else if (RegapplyVO.APPROVE_STATE.equals(fieldCode[j])) {
					// 单据状态
					value = TRNConst.getBillStateName(bill.getApprove_state() == null ? IPfRetCheckInfo.PASSING : bill.getApprove_state());
				} else if (RegapplyVO.PROBATION_TYPE.equals(fieldCode[j])) {
					// 试用类型
					value = getProbationType(bill.getProbation_type() == null ? 1 : bill.getProbation_type());
				} else if (RegapplyVO.TRIALRESULT.equals(fieldCode[j])) {
					// 试用结果
					value = getTrialresult(bill.getTrialresult());
				} else if (RegapplyVO.PK_PSNJOB.equals(fieldCode[j])) {
					// 人员姓名
					value = VOUtils.getDocName(PsndocVO.class, bill.getPk_psndoc());
				} else if (RegapplyVO.OLDPK_ORG.equals(fieldCode[j])) {
					// 旧组织
					value = VOUtils.getDocName(OrgVO.class, bill.getOldpk_org());
				} else if (RegapplyVO.NEWPK_ORG.equals(fieldCode[j])) {
					// 新组织
					value = VOUtils.getDocName(OrgVO.class, bill.getNewpk_org());
				} else if (RegapplyVO.OLDPK_DEPT.equals(fieldCode[j])) {
					// 旧部门
					value = VOUtils.getDocName(DeptVO.class, bill.getOldpk_dept());
				} else if (RegapplyVO.NEWPK_DEPT.equals(fieldCode[j])) {
					// 新部门
					value = VOUtils.getDocName(DeptVO.class, bill.getNewpk_dept());
				} else if (RegapplyVO.OLDPK_PSNCL.equals(fieldCode[j])) {
					// 旧人员类别
					value = VOUtils.getDocName(PsnClVO.class, bill.getOldpk_psncl());
				} else if (RegapplyVO.NEWPK_PSNCL.equals(fieldCode[j])) {
					// 新人员类别
					value = VOUtils.getDocName(PsnClVO.class, bill.getNewpk_psncl());
				} else if (RegapplyVO.OLDPK_POST.equals(fieldCode[j])) {
					// 旧岗位
					value = VOUtils.getDocName(PostVO.class, bill.getOldpk_post());
				} else if (RegapplyVO.NEWPK_POST.equals(fieldCode[j])) {
					// 新岗位
					value = VOUtils.getDocName(PostVO.class, bill.getNewpk_post());
				} else if (RegapplyVO.OLDPK_JOB.equals(fieldCode[j])) {
					// 旧职务
					value = VOUtils.getDocName(JobVO.class, bill.getOldpk_job());
				} else if (RegapplyVO.NEWPK_JOB.equals(fieldCode[j])) {
					// 新职务
					value = VOUtils.getDocName(JobVO.class, bill.getNewpk_job());
				} else {
					value = "";
				}
				hm.put(fieldCode[j] + i, new String[]{value});
			}
		}
		return hm;
	}

	@Override
	public <T extends AggregatedValueObject> void deleteBatchBill(T... billvos) throws BusinessException {

		PfBusinessLock pfLock = null;
		IFlowBizItf flowItf = getFlowBizItf(billvos[0].getParentVO());
		try {
			// 加锁
			pfLock = new PfBusinessLock();
			pfLock.lock(new VOsLockData(billvos, flowItf.getBilltype()), new VOsConsistenceCheck(billvos, flowItf.getBilltype()));
			// 自定义校验器
			DefaultValidationService vService = new DefaultValidationService();
			createCustomValidators(vService, DELETE);
			SuperVO[] headvos = getHeadVO(billvos).toArray(new SuperVO[0]);
			vService.validate(headvos);
			getMDPersistenceService().deleteBillFromDB(billvos);
		} finally {
			if (pfLock != null) {
				// 释放锁
				pfLock.unLock();
			}
		}
	}

	/**
	 * 删除单据
	 *
	 * @param <T>
	 * @param billvo
	 * @throws BusinessException
	 */
	@Override
	public <T extends AggregatedValueObject> void deleteBill(T billvo) throws BusinessException {

		PfBusinessLock pfLock = null;
		IFlowBizItf flowItf = getFlowBizItf(billvo.getParentVO());
		try {
			// 加锁
			pfLock = new PfBusinessLock();
			pfLock.lock(new VOLockData(billvo, flowItf.getBilltype()), new VOConsistenceCheck(billvo, flowItf.getBilltype()));
			// 自定义校验器
			DefaultValidationService vService = new DefaultValidationService();
			createCustomValidators(vService, DELETE);
			SuperVO[] headvos = getHeadVO(billvo).toArray(new SuperVO[0]);
			vService.validate(headvos);
			getMDPersistenceService().deleteBillFromDB(billvo);
		} finally {
			if (pfLock != null) {
				// 释放锁
				pfLock.unLock();
			}
		}
	}

	// 删除审批意见的操作
	private void deleteOldWorknote(AggRegapplyVO vo) throws BusinessException {

		getIHrPf().deleteWorkflowNote(vo);

	}

	@Override
	public PfProcessBatchRetObject directApprove(AggregatedValueObject[] billvos, String approveNote, int approveResult)
			throws BusinessException {
		PFBatchExceptionInfo errInfo = new PFBatchExceptionInfo();
		ArrayList<AggregatedValueObject> bill = new ArrayList<AggregatedValueObject>();

		for (int i = 0; i < billvos.length; i++) {
			try {
				AggregatedValueObject retVO =
						NCLocator
								.getInstance()
								.lookup(IRegmngManageService.class)
								.singleDirectApprove_RequiresNew(billvos[i], PubEnv.getPk_user(), PubEnv.getServerTime(), approveNote,
										approveResult);
				bill.add(retVO);
			} catch (VersionConflictException ve) {
				errInfo.putErrorMessage(i, billvos[i], ve.getBusiObject() == null ? "" : ve.getBusiObject().toString());
				Logger.error(ve.getMessage(), ve);
			} catch (Exception e) {
				errInfo.putErrorMessage(i, billvos[i], StringUtils.isBlank(e.getMessage()) ? "" : e.getMessage());
				Logger.error(e.getMessage(), e);
			}
		}

		return new PfProcessBatchRetObject(bill.toArray(new AggregatedValueObject[0]), errInfo);
	}

	public AggRegapplyVO[] doApprove(AggregatedValueObject[] vosin) throws BusinessException {
		// 开启新事物更新单据状态
//        AggRegapplyVO vos[] = NCLocator.getInstance().lookup(IRegmngManageService.class).updateBill_RequiresNew(vosin);
		AggRegapplyVO vos[] = updateBill_RequiresNew(vosin);
		// 为了支持消息模板上的审批和移动审批，将执行单据的操作移至后台处理
		return execBill(vos);
	}

	/**
	 * 开启新事务，更新单据状态
	 *
	 * @param vosin
	 * @return
	 * @throws BusinessException
	 * @author heqiaoa 2014-11-17
	 */
	public AggRegapplyVO[] updateBill_RequiresNew(AggregatedValueObject[] vosin) throws BusinessException {
		AggRegapplyVO[] vos = new AggRegapplyVO[vosin.length];
		for (int i = 0; i < vosin.length; i++) {
			vos[i] = (AggRegapplyVO) vosin[i];
		}
		validate(vos);
		for (int i = 0; vos != null && i < vos.length; i++) {
			vos[i] = updateBill(vos[i], false);
		}
		return vos;
	}

	public AggregatedValueObject[] doCallBack(AggregatedValueObject[] vos) throws BusinessException {
		for (int i = 0; vos != null && i < vos.length; i++) {
			vos[i] = updateBill(vos[i], false);
		}
		return vos;
	}

	public AggRegapplyVO[] doCommit(AggRegapplyVO[] vos) throws BusinessException {

		for (int i = 0; vos != null && i < vos.length; i++) {
			RegapplyVO billvo = (RegapplyVO) vos[i].getParentVO();
			if (!isHasFile(billvo)) {
				throw new BusinessException(ResHelper.getString("6009reg", "06009reg0047")/* @res "单据没有上传附件" */);
			}
			// 更新单据状态
			billvo.setApprove_state(IPfRetCheckInfo.COMMIT);
			vos[i].setParentVO(billvo);
			vos[i] = updateBill(vos[i], false);
		}
		String pk_org = ((RegapplyVO) vos[0].getParentVO()).getPk_org();
		Integer approvetype = HRConstEnum.APPROVE_TYPE_FORCE_WORK_FLOW;
		try {
			approvetype = SysInitQuery.getParaInt(pk_org, IHrPf.hashBillTypePara.get(TRNConst.BillTYPE_REG));
		} catch (Exception e) {
			Logger.error(e.getMessage(), e);
		}
		if (approvetype != null && approvetype == HRConstEnum.APPROVE_TYPE_FORCE_DIRECT) {
			/** modify start：入职直批发送通知方式修改 2013.4.10 yunana */
			// 审批方式为直批时发送通知
			// HiSendMsgHelper.sendMessage("1001Z7APP00000000003", PubEnv.getPk_group(), ((RegapplyVO)
			// vos[0].getParentVO()).getPk_org(),
			// createUserValue(vos), TRNConst.FIELDCODE_REG, vos == null ? 0 : vos.length);
//            String tempCode = HICommonValue.msgcode_zhuanzheng_approve;// 入职直批通知消息模板源编码
//            HiSendMsgHelper.sendMessage1(tempCode, vos, pk_org);
			/** modify end:2014.4.10 */
		}
		return vos;
	}

	public AggRegapplyVO[] doDelete(AggRegapplyVO[] vos) throws BusinessException {
		IBillcodeManage billcodeMng = NCLocator.getInstance().lookup(IBillcodeManage.class);
		for (AggRegapplyVO vo : vos) {
			String billType = (String) vo.getParentVO().getAttributeValue(RegapplyVO.PK_BILLTYPE);
			String pk_group = (String) vo.getParentVO().getAttributeValue(RegapplyVO.PK_GROUP);
			String pk_org = (String) vo.getParentVO().getAttributeValue(RegapplyVO.PK_ORG);
			String bill_code = (String) vo.getParentVO().getAttributeValue(RegapplyVO.BILL_CODE);
			if (isAutoGenerateBillCode(billType, pk_group, pk_org)) {
				billcodeMng.returnBillCodeOnDelete(billType, pk_group, pk_org, bill_code, null);
			}
			deleteOldWorknote(vo);
			deleteBill(vo);
		}
		return vos;
	}

	/**
	 * 处理单据信息_执行
	 */
	public void doPerfromBill_RequiresNew(AggRegapplyVO aggVO) throws BusinessException {
		if (aggVO == null) {
			return;
		}
		RegapplyVO vo = (RegapplyVO) aggVO.getParentVO();
		if (vo.getTrialresult() == null) {
			throw new BusinessException(ResHelper.getString("6009reg", "06009reg0032")/* @res "试用结果不能为空!" */);
		}
		switch (vo.getTrialresult()) {
			case TRNConst.TRIALRESULT_PASS:// 试用结果－转正
				updateTrialForPASS(vo);
				break;
			case TRNConst.TRIALRESULT_DELAY:// 试用结果－延长试用期限
				updateTrialForDelay(vo);
				break;
			case TRNConst.TRIALRESULT_FALL:// 试用结果－未通过试用
				updateTrialForFall(vo);
				break;
			default:
				break;
		}

		// 人员变动时，如果人员编码设置了后编码规则，根据参数更新人员编码
		updatePsncode_Apply(vo.getPk_psndoc(), vo.getPk_org(), vo);

		// 更新单据状态为已执行
		aggVO.getParentVO().setAttributeValue(RegapplyVO.APPROVE_STATE, HRConstEnum.EXECUTED);
		getServiceTemplate().update(aggVO, false);

		// 转正执行(生效)的工作量统计与满意度调查埋点
		WorkLoadCountUtil.count(aggVO, BusiActionConst.EFFECT, TRNConst.BillTYPE_REG);
		SatisfactSurveryUtil.fireSurvey(aggVO, BusiActionConst.EFFECT, TRNConst.BillTYPE_REG);
	}

	// 人员转正时，如果人员编码设置了后编码规则，根据参数更新人员编码
	public void updatePsncode_Apply(String pk_psndoc, String pk_hrorg, RegapplyVO regapplyvo) throws BusinessException {
		// 参数为是的情况下才考虑这些
		UFBoolean para = SysinitAccessor.getInstance().getParaBoolean(pk_hrorg, "TRN0005");
		if (para != null && para.booleanValue()) {
			BillCodeContext billContext =
					NCLocator.getInstance().lookup(IBillcodeManage.class)
							.getBillCodeContext(HICommonValue.NBCR_PSNDOC_CODE, PubEnv.getPk_group(), pk_hrorg);
			// 人员编码规则设置为后编码
			if (billContext != null && !billContext.isPrecode()) {
				// 如果设置的是后编码，当人员变动时，需要判断编码规则中定义的业务实体的值是否发生了变化，来决定是否重新生成人员编码
				HashMap<String, Object> map = getCodeRule_Apply(pk_hrorg, regapplyvo);
				if (map == null) {
					return;
				}
				boolean ischange = (boolean) map.get("ischange");

				if (ischange) {
					PsndocVO[] psndocvo =
							(PsndocVO[]) NCLocator.getInstance().lookup(IPersistenceRetrieve.class)
									.retrieveByClause(null, PsndocVO.class, " pk_psndoc = '" + pk_psndoc + "' ");
					IHrBillCode service = NCLocator.getInstance().lookup(IHrBillCode.class);
					PsnJobVO psnjobvo = (PsnJobVO) map.get("psnjobvo");
					String[] strCode =
							service.getLeveledBillCode(HICommonValue.NBCR_PSNDOC_CODE, PubEnv.getPk_group(), pk_hrorg, psnjobvo, 1);
					psndocvo[0].setCode(strCode[0]);
					psndocvo[0].setStatus(VOStatus.UPDATED);
					NCLocator.getInstance().lookup(IPersistenceUpdate.class).updateVO(null, psndocvo[0], new String[]{PsndocVO.CODE}, null);
				}
			}
		}
	}

	// 如果设置的是后编码，当人员变动时，需要判断编码规则中定义的业务实体的值是否发生了变化，来决定是否重新生成人员编码
	public HashMap<String, Object> getCodeRule_Apply(String pk_hrorg, RegapplyVO regapplyvo) throws BusinessException {
		HashMap<String, Object> map = new HashMap<String, Object>();
		boolean ischange = false;
		BillCodeRuleVO rulevo = getBillCodeRuleVOFromDB(HICommonValue.NBCR_PSNDOC_CODE, PubEnv.getPk_group(), pk_hrorg);
		BillCodeElemVO[] elems = rulevo.getElems();
		// 针对业务实体elemtype=1的字段抓取出来，需要对比变动前后的值来决定是否重新生成人员编码
		if (!ArrayUtils.isEmpty(elems)) {
			List<String> liststr = new ArrayList<String>();
			for (int i = 0; i < elems.length; i++) {
				if (elems[i].getElemtype() == 1) {
					liststr.add(elems[i].getElemvalue());
				}
			}
			String[] str = liststr.toArray(new String[0]);
			if (ArrayUtils.isEmpty(str)) {// 定义的后编码规则中没有选择业务实体，则编码一直都不需要重新生成
				return null;
			}

			PsnJobVO psnjobvo = new PsnJobVO();
			for (int i = 0; i < str.length; i++) {
				String name = str[i];
				String newdata =
						regapplyvo.getAttributeValue("new" + name) == null ? "" : regapplyvo.getAttributeValue("new" + name).toString();
				String olddata =
						regapplyvo.getAttributeValue("old" + name) == null ? "" : regapplyvo.getAttributeValue("old" + name).toString();
				if (!newdata.equals(olddata)) {
					ischange = true;
					psnjobvo.setAttributeValue(name, newdata);
				}
			}

			map.put("ischange", ischange);
			map.put("psnjobvo", psnjobvo);

		}
		return map;
	}

	/**
	 * 根据单据类型编码得到该单据类型的单据号规则。
	 *
	 * @return
	 * @throws SQLException
	 * @throws NamingException
	 * @throws SystemException
	 * @throws ValidationException
	 */
	private BillCodeRuleVO getBillCodeRuleVOFromDB(String nbcrcode, String pk_group, String pk_org) throws BusinessException {
		BillCodeRuleVO rulevo;
		try {
			IBillcodeRuleQryService service = NCLocator.getInstance().lookup(IBillcodeRuleQryService.class);
			rulevo = service.qryBillCodeRule(nbcrcode, pk_group, pk_org);
		} catch (Exception e) {
			Logger.error("Error occurs while querying BillCodeRule", e);
			throw new BusinessException("Error occurs while querying BillCodeRule", e);
		}
		if (rulevo == null)
			throw new nc.vo.pub.ValidationException(nc.bs.ml.NCLangResOnserver.getInstance().getStrByID("101704", "UPP101704-000009", null,
					new String[]{nbcrcode}));// /*@res
		// "该单据类型还没有定义编码规则，获得单据号失败：单据类型编码为{0}"*/+billTypeCode+"'");
		return rulevo;
	}

	public Object doPush(AggRegapplyVO vo) throws BusinessException {
		return vo;
	}

	/**
	 * 推其他业务单据
	 *
	 * @param aggVO
	 * @throws BusinessException
	 */
	public void doPushBill_RequiresNew(AggRegapplyVO aggVO) throws BusinessException {

		HashMap<String, String> hashPara = new HashMap<String, String>();
		hashPara.put(PfUtilBaseTools.PARAM_NOFLOW, PfUtilBaseTools.PARAM_NOFLOW);
		AggRegapplyVO agg = queryByPk(aggVO.getParentVO().getPrimaryKey());
		NCLocator.getInstance().lookup(IplatFormEntry.class).processAction("PUSH", TRNConst.BillTYPE_REG, null, agg, null, hashPara);
	}

	public AggregatedValueObject[] doUnapprove(AggregatedValueObject[] vos) throws BusinessException {
		List<String> regPKList = new ArrayList<String>();
		for (int i = 0; i < vos.length; i++) {
			regPKList.add(((RegapplyVO) vos[i].getParentVO()).getPk_hi_regapply());
		}
		if (!regPKList.isEmpty()) {
			InSQLCreator isc = new InSQLCreator();
			String insql = isc.getInSQL(regPKList.toArray(new String[0]));
			String strCondition = "pk_hi_regapply in (" + insql + ")";
			RegapplyVO[] regApplyVOs =
					(RegapplyVO[]) NCLocator.getInstance().lookup(IPersistenceRetrieve.class)
							.retrieveByClause(null, RegapplyVO.class, strCondition);
			for (int i = 0; i < regApplyVOs.length; i++) {
				int approvestate = regApplyVOs[i].getApprove_state();

				checkPFPassingState(approvestate);

				if (approvestate == HRConstEnum.EXECUTED) {
					throw new BusinessException(ResHelper.getString("6009tran", "06009tran0209")/* "已执行的单据不能取消审批！" */);
				}
			}
		}
		for (int i = 0; vos != null && i < vos.length; i++) {
			vos[i] = updateBill(vos[i], false);
		}
		return vos;
	}

	public void checkPFPassingState(int pfsate) throws BusinessException {
		// guoqt在审批节点操作单据是走nc.ui.hr.pf.action.PFUnApproveAction的doAction()方法，但是在消息中心的工作任务中是走该方法，所以要同时判断单据审批通过还是弃审，两种情况都不能取消审批
		if (IPfRetCheckInfo.NOPASS == pfsate) {
			throw new BusinessException(ResHelper.getString("6007entry", "16007entry0014")
					/* @res "单据审批未通过,不能取消审批！" */);
		}
	}

	/**
	 * 为了支持消息模板上的审批和移动审批，将执行单据的操作移至后台处理 将原来在前台Model中实现的execBills函数移至后台实现
	 *
	 * @param vos
	 * @return
	 * @throws BusinessException
	 * @author heqiaoa 2014-11-18
	 */
	private AggRegapplyVO[] execBill(AggRegapplyVO vos[]) throws BusinessException {
		ArrayList<AggRegapplyVO> al = new ArrayList<AggRegapplyVO>();
		ArrayList<AggRegapplyVO> allvo = new ArrayList<AggRegapplyVO>();
		for (int i = 0; i < vos.length; i++) {
			AggRegapplyVO agg = (AggRegapplyVO) vos[i];
			Integer apprState = ((RegapplyVO) agg.getParentVO()).getApprove_state();
			UFLiteralDate effectDate = ((RegapplyVO) agg.getParentVO()).getRegulardate();
			if (effectDate != null && effectDate.compareTo(PubEnv.getServerLiteralDate()) <= 0 && apprState != null
					&& apprState == IPfRetCheckInfo.PASSING) {
				al.add(agg);
			}
			allvo.add(agg);
		}

		ArrayList<AggRegapplyVO> bills = new ArrayList<AggRegapplyVO>();
		if (al.size() > 0) {
			// 为了传入合适的参数进行编制校验，这里用pk_org和pk_group构造一个LoginContext
			LoginContext tempContext = new LoginContext();
			AggRegapplyVO aggvo = al.get(0);
			tempContext.setPk_org(((RegapplyVO) aggvo.getParentVO()).getPk_org());
			tempContext.setPk_group(((RegapplyVO) aggvo.getParentVO()).getPk_group());
			// 返回一个map 包括执行成功的单据，及执行不成功的信息
			HashMap<String, Object> result =
					NCLocator.getInstance().lookup(IRegmngManageService.class).execBills(al.toArray(new AggRegapplyVO[0]), tempContext, false);
			bills = (ArrayList<AggRegapplyVO>) result.get(TRNConst.RESULT_BILLS);
			String msg = (String) result.get(TRNConst.RESULT_MSG);
			if (!StringUtils.isBlank(msg)) {
				// 构造NCMessage
				NCMessage ncMessage = new NCMessage();
				MessageVO messageVO = new MessageVO();
				messageVO.setMsgsourcetype(IDefaultMsgConst.NOTICE);// 消息源类型
				messageVO.setReceiver(PubEnv.getPk_user());// 设置接收人 多个接收人之间以逗号隔开
				messageVO.setIsdelete(UFBoolean.FALSE);// 接收删除标记
				messageVO.setSender(INCSystemUserConst.NC_USER_PK);
				// 如果发送时间为空则默认为服务器时间
				messageVO.setSendtime(PubEnv.getServerTime());
				messageVO.setDr(0);
				messageVO.setSubject(ResHelper.getString("6007entry", "16007entry0015")/*
				 * res "单据审批失败"
				 */);
				messageVO.setContent(msg);
				ncMessage.setMessage(messageVO);
				NCMessage[] message = new NCMessage[1];
				message[0] = ncMessage;
				try {
					MessageCenter.sendMessage(message);
				} catch (Exception e) {
					Logger.error(e.getMessage(), e);
				}
			}
		}

		// 将执行成功的和不成功的合并
		if (bills != null && bills.size() > 0)// 若没有执行成功的单据，则直接将审批通过的单据返回回去刷新界面
		{
			for (int i = 0; i < allvo.size(); i++) {
				AggRegapplyVO aggivo = allvo.get(i);
				for (int j = 0; j < bills.size(); j++) {
					AggRegapplyVO aggjvo = allvo.get(j);
					if (aggivo.getParentVO().getPrimaryKey().equals(aggjvo.getParentVO().getPrimaryKey())) {
						allvo.remove(i);
					}
				}
			}
			vos = (AggRegapplyVO[]) ArrayUtils.addAll(allvo.toArray(new AggRegapplyVO[0]), bills.toArray(new AggRegapplyVO[0]));
		}

		return vos;
	}

	/**
	 * 执行单据
	 *
	 * @param billVOs
	 * @param context
	 * @param isRunBackgroundTask
	 * @return HashMap<String, Object>
	 * @throws BusinessException
	 */
	public HashMap<String, Object> execBills(AggRegapplyVO[] billVOs, LoginContext context, boolean isRunBackgroundTask)
			throws BusinessException {
		HashMap<String, Object> result = new HashMap<String, Object>();
		StringBuffer sb = new StringBuffer();// 错误信息

		AggregatedValueObject[] retVOs = null;
		if (ArrayUtils.isEmpty(billVOs)) {
			return result;
		}
		retVOs = validateBudget(billVOs, context);

		// 添加一段逻辑,将编制校验没通过的单据,也加入到错误提示中
		for (int i = 0; i < billVOs.length; i++) {
			if (isExit(retVOs, billVOs[i])) {
				continue;
			}
			sb.append(ResHelper.getString("6009reg", "06009reg0033"/* @res "单据{0}由于编制校验未通过不能成功执行 " */, (String) billVOs[i].getParentVO()
							.getAttributeValue(RegapplyVO.BILL_CODE))
					/* + "<br>" */);
		}

		if (retVOs == null || retVOs.length == 0) {
			// 两部分都没有可执行单据,直接返回
			String msg = sb.length() == 0 ? "" : sb.toString();
			result.put(TRNConst.RESULT_MSG, isRunBackgroundTask ? msg : msg.replaceAll("<br>", '\n' + ""));
			result.put(TRNConst.RESULT_BILLS, null);
			return result;
		}

		// 只对单据进行编制校验
		ArrayList<AggRegapplyVO> passBills = new ArrayList<AggRegapplyVO>();// 调配执行成功的单据
		IRegmngManageService regService = NCLocator.getInstance().lookup(IRegmngManageService.class);
		for (int i = 0; i < retVOs.length; i++) {
			try {
				// 转正执行
				doPerfromBill_RequiresNew((AggRegapplyVO) retVOs[i]);
				// 重新查询一遍，可以
				passBills.add((AggRegapplyVO) queryByPk(retVOs[i].getParentVO().getPrimaryKey()));
			} catch (Exception e) {
				Logger.error(e.getMessage(), e);
				String billcode = (String) retVOs[i].getParentVO().getAttributeValue(RegapplyVO.BILL_CODE);
				if (StringUtils.isBlank(e.getMessage())) {
					sb.append(i + 1 + ":" + ResHelper.getString("6009reg", "06009reg0034"/*
					 * @res
					 * "单据{0}由于如下未知异常[{1}]不能成功执行,具体异常信息请查看日志"
					 */, billcode, e.getMessage()) /*
					 * +
					 * "<br>"
					 */);
				} else {
					if (e.getMessage().indexOf(billcode) < 0) {
						// 如果异常信息中没有出现单据号,则重组异常信息
						sb.append(i + 1 + ":" + ResHelper.getString("6009reg", "06009reg0034"/*
						 * @res
						 * "单据{0}由于如下未知异常[{1}]不能成功执行,具体异常信息请查看日志"
						 */, billcode, e.getMessage()) /*
						 * +
						 * "<br>"
						 */);
					} else {
						sb.append(i + 1 + ":" + e.getMessage()/* + "<br>" */);
					}
				}
				continue;
			}

			try {
				// 改为服务内重新查询单据
				doPushBill_RequiresNew((AggRegapplyVO)retVOs[i]);
			} catch (Exception e) {
				Logger.error(e.getMessage(), e);
			}
		}
		// 执行完成后,发送通知
		// 1)发送转正的通知,按照转正后组织发送 1001Z7PSN00000000003
		// key-org value-bill_list
		HashMap<String, ArrayList<AggRegapplyVO>> hmTrans = new HashMap<String, ArrayList<AggRegapplyVO>>();
		for (AggregatedValueObject bill : retVOs) {
			String pk_org = (String) bill.getParentVO().getAttributeValue(RegapplyVO.PK_ORG);
			if (hmTrans.get(pk_org) == null) {
				hmTrans.put(pk_org, new ArrayList<AggRegapplyVO>());
			}
			hmTrans.get(pk_org).add((AggRegapplyVO) bill);
		}
		for (String key : hmTrans.keySet()) {
			if (hmTrans.get(key) == null || hmTrans.get(key).size() <= 0) {
				continue;
			}

			String tempCode = HICommonValue.msgcode_zhuanzheng;
			HiSendMsgHelper.sendMessage1(tempCode, hmTrans.get(key).toArray(new AggRegapplyVO[0]), key);
		}

		// end
		String msg = sb.length() == 0 ? "" : sb.toString();
		result.put(TRNConst.RESULT_MSG, isRunBackgroundTask ? msg : msg.replaceAll("<br>", '\n' + ""));
		result.put(TRNConst.RESULT_BILLS, passBills);
		return result;
	}

	@Override
	public String getBillIdSql(int iBillStatus, String billType) throws BusinessException {

		String strWorkFlowWhere = getIHrPf().getBillIdSql(iBillStatus, billType);
		if (StringUtils.isNotBlank(strWorkFlowWhere)) {
			strWorkFlowWhere = RegapplyVO.PK_HI_REGAPPLY + " in (" + strWorkFlowWhere + ") ";
		}
		return strWorkFlowWhere;
	}

	/**
	 * 获取当前最大的流水号
	 *
	 * @param i
	 * @return String
	 * @throws BusinessException
	 */
	private String getFlowCode(String code, int i) throws BusinessException {

		Integer value = Integer.valueOf(code);
		return StringUtils.leftPad(value + i + "", 5, '0');
	}

	/**
	 * 获取主实体VO
	 *
	 * @param objects
	 * @return
	 */
	private List<SuperVO> getHeadVO(Object objects) {

		List<SuperVO> headls = new ArrayList<SuperVO>();
		if (objects instanceof AggregatedValueObject[] && ((AggregatedValueObject[]) objects).length >= 1) {
			AggregatedValueObject[] objs = (AggregatedValueObject[]) objects;
			for (int i = 0; i < objs.length; i++) {
				headls.add((SuperVO) objs[i].getParentVO());
			}
		} else {
			AggregatedValueObject obj = (AggregatedValueObject) objects;
			headls.add((SuperVO) obj.getParentVO());
		}
		return headls;
	}

	private IHrBillCode getHrBillCode() {

		return NCLocator.getInstance().lookup(IHrBillCode.class);
	}

	private IHrPf getIHrPf() {

		return NCLocator.getInstance().lookup(IHrPf.class);
	}

	private IPersistenceRetrieve getIPersistenceRetrieve() {

		return NCLocator.getInstance().lookup(IPersistenceRetrieve.class);
	}

	private IPersistenceUpdate getIPersistenceUpdate() {

		return NCLocator.getInstance().lookup(IPersistenceUpdate.class);
	}

	private TrnRegItemVO getItemByItemkey(TrnRegItemVO[] itemvos, String itemKey) {
		for (int i = 0; itemvos != null && i < itemvos.length; i++) {
			if (itemKey.equals(itemvos[i].getItemkey())) {
				return itemvos[i];
			}
		}
		return null;
	}

	/**
	 * 根据组织关系主键与任职ID得到某子集的最新记录
	 *
	 * @param <T>
	 * @param className
	 * @param pk_psnorg
	 * @param assgid
	 * @return < T extends SuperVO > T
	 * @throws BusinessException
	 */
	private <T> T[] getLastVO(Class<T> className, String pk_psnorg, Integer assgid) throws BusinessException {

		String where = " pk_psnorg = '" + pk_psnorg + "' and lastflag = 'Y' ";
		if (assgid != null) {
			where += " and assgid = " + assgid.intValue();
		}
		return getServiceTemplate().queryByCondition(className, where);
	}

	private String getMsg(RegapplyVO billvo) throws BusinessException {

		// 对于审批通过的单据,校验所有必输的项目是否都输入完毕
		SuperVO[] itemvos =
				TrnDelegator.getIItemSetQueryService().queryItemSetByOrg(TRNConst.REGITEM_BEANID, billvo.getPk_group(), billvo.getPk_org(),
						billvo.getProbation_type());
		IBean ibean = BeanUtil.getBeanEntity(TRNConst.REGITEM_BEANID);
		List<IItemSetAdapter> iitemadpls = BeanUtil.getBizImpObjFromVo(ibean, IItemSetAdapter.class, itemvos);
		for (IItemSetAdapter item : iitemadpls) {
			if (item == null || item.getItemkey().startsWith("old")) {
				// 前项目不校验
				continue;
			}
			if (item.getIsnotnull().booleanValue() && isNull(billvo.getAttributeValue(item.getItemkey()))) {
				return '\n' + billvo.getBill_code();
			}
		}
		return "";
	}

	private IPersistenceUpdate getPersistenceUpdate() {

		return NCLocator.getInstance().lookup(IPersistenceUpdate.class);
	}

	private String getProbationType(Integer state) {

		switch (state) {
			case TRNConst.PROBATIONTYPE_ENTRY:
				return ResHelper.getString("6009reg", "06009reg0035")/* @res "入职试用" */;
			case TRNConst.PROBATIONTYPE_TRANS:
				return ResHelper.getString("6009reg", "06009reg0036")/* @res "转岗试用" */;
		}
		return ResHelper.getString("6009reg", "06009reg0035")/* @res "入职试用" */;
	}

	private SimpleDocServiceTemplate getServiceTemplate() {

		if (serviceTemplate == null) {
			serviceTemplate = new SimpleDocServiceTemplate(DOC_NAME);
		}
		return serviceTemplate;
	}

	private String getTrialresult(Integer state) {

		if (state == null) {
			return "";
		}
		switch (state) {
			case TRNConst.TRIALRESULT_PASS:
				return ResHelper.getString("6009reg", "06009reg0014")/* @res "转正" */;
			case TRNConst.TRIALRESULT_DELAY:
				return ResHelper.getString("6009reg", "06009reg0037")/* @res "延长试用期限" */;
			case TRNConst.TRIALRESULT_FALL:
				return ResHelper.getString("6009reg", "06009reg0038")/* @res "未通过试用" */;
		}
		return "";
	}

	/**
	 * 根据组织关系主键与任职ID得到某子集的最新记录
	 *
	 * @param <T>
	 * @param className
	 * @param pk_psnorg
	 * @param assgid
	 * @return < T extends SuperVO > T
	 * @throws BusinessException
	 */
	private <T> T[] getValidVO(Class<T> className, String pk_psnorg, Integer assgid) throws BusinessException {

		String where = " pk_psnorg = '" + pk_psnorg + "' and endflag = 'N' ";
		if (assgid != null) {
			where += " and assgid = " + assgid.intValue();
		}
		return getServiceTemplate().queryByCondition(className, where);
	}

	private boolean hasFile(NCFileNode node) {
		if (node.getChildCount() <= 0) {
			return false;
		}

		for (int i = 0; i < node.getChildCount(); i++) {
			if (!((NCFileNode) node.getChildAt(i)).isFolder()) {
				return true;
			} else if (hasFile((NCFileNode) node.getChildAt(i))) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 单据保存
	 *
	 * @param <T>
	 * @param billvo
	 * @return
	 * @throws BusinessException
	 */
	@Override
	public <T extends AggregatedValueObject> T insertBill(T billvo) throws BusinessException {

		PfBusinessLock pfLock = null;
		IFlowBizItf flowItf = getFlowBizItf(billvo.getParentVO());
		// 提交单据号
		RegapplyVO head = (RegapplyVO) billvo.getParentVO();

		try {
			// 加锁
			pfLock = new PfBusinessLock();
			pfLock.lock(new VOLockData(billvo, flowItf.getBilltype()), new VOConsistenceCheck(billvo, flowItf.getBilltype()));

			checkBillCodeRepeat(billvo);

			// 自定义校验器
			DefaultValidationService vService = new DefaultValidationService();
			createCustomValidators(vService, INSERT);
			SuperVO[] headvos = getHeadVO(billvo).toArray(new SuperVO[0]);
			vService.validate(headvos);
			// 设置审计信息
			billvo.getParentVO().setStatus(VOStatus.NEW);
			setAuditInfoAndTs((SuperVO) billvo.getParentVO(), true);
			Glbdef2VO[] glbdef1VO = (Glbdef2VO[]) billvo.getChildrenVO();
			billvo.setChildrenVO(null);
			String pk = getMDPersistenceService().saveBill(billvo);
			billvo.getParentVO().setPrimaryKey(pk);
			
			if(glbdef1VO != null && glbdef1VO.length > 0) {
				for(Glbdef2VO vo : glbdef1VO) {
					vo.setStatus(VOStatus.NEW);
					vo.setPk_hi_regapply(pk);
				}
				String[] pks = getMDPersistenceService().saveBill(glbdef1VO);
			} else {
				DefdocVO[] defdocVOs = (DefdocVO[]) NCLocator.getInstance().lookup(IPersistenceRetrieve.class).retrieveByClause(null, DefdocVO.class, "pk_defdoclist = (select pk_defdoclist from bd_defdoclist where code = 'HRTRN099' and nvl(dr,0) = 0) and nvl(dr,0) = 0 order by code");
				if(defdocVOs != null && defdocVOs.length > 0) {
					List<Glbdef2VO> glbdef1List = new ArrayList();
					for(DefdocVO vo : defdocVOs) {
						Glbdef2VO gvo = new Glbdef2VO();
						gvo.setAttributeValue("glbdef1", vo.getPk_defdoc());
						gvo.setAttributeValue("glbdef2", vo.getDef1());
						gvo.setAttributeValue("glbdef3", vo.getDef2());
						gvo.setAttributeValue("glbdef4", vo.getDef3());
						gvo.setAttributeValue("glbdef5", vo.getDef4());
						gvo.setPk_hi_regapply(pk);
						gvo.setStatus(VOStatus.NEW);
						glbdef1List.add(gvo);
					}
					String[] pks = getMDPersistenceService().saveBill(glbdef1List.toArray(new Glbdef2VO[0]));
				}
			}
			
			if (isAutoGenerateBillCode(head.getPk_billtype(), head.getPk_group(), head.getPk_org())) {
				getHrBillCode().commitPreBillCode(head.getPk_billtype(), head.getPk_group(), head.getPk_org(), head.getBill_code());
			}
		} catch (BillCodeRepeatBusinessException be) {
			String[] codes = be.getRepeatCodes();
			if (isAutoGenerateBillCode(TRNConst.BillTYPE_REG, PubEnv.getPk_group(), flowItf.getPkorg()) && codes != null) {
				IBillcodeManage billcode = NCLocator.getInstance().lookup(IBillcodeManage.class);
				for (int i = 0; i < codes.length; i++) {
					try {
						billcode.AbandonBillCode_RequiresNew(TRNConst.BillTYPE_REG, PubEnv.getPk_group(), flowItf.getPkorg(), codes[i]);
					} catch (Exception e2) {
						Logger.error(e2.getMessage(), e2);
					}
				}
			}
			throw be;
		} catch (Exception e) {

			// 发生异常如果是自动生成单据号,则会滚单据号
			if (isAutoGenerateBillCode(head.getPk_billtype(), PubEnv.getPk_group(), flowItf.getPkorg())) {
				NCLocator.getInstance().lookup(IHrBillCode.class)
						.rollbackPreBillCode(head.getPk_billtype(), PubEnv.getPk_group(), flowItf.getPkorg(), flowItf.getBillNo());
			}

			Logger.error(e.getMessage(), e);
			throw new BusinessException(e.getMessage());
		} finally {
			if (pfLock != null) {
				// 释放锁
				pfLock.unLock();
			}
		}
		return billvo;
	}

	private boolean isAutoGenerateBillCode(String billType, String pk_group, String pk_org) throws BusinessException {

		BillCodeContext billCodeContext = HiCacheUtils.getBillCodeContext(billType, pk_group, pk_org);
		return billCodeContext != null;
	}

	/**
	 * 校验当前驱动是否允许
	 *
	 * @param srcBilltype  来源单据类型PK
	 * @param srcBillVO    源单据VO
	 * @param srcAction    来源动作编码，比如"APPROVE"等
	 * @param destBillType 目的单据类型PK
	 * @param beDrivedActionName 被驱动动作编码，比如"WRITE"等
	 * @return true允许；false不允许
	 * @throws BusinessException
	 */
	public boolean isEnableDrive(String srcBilltype, AggregatedValueObject srcBillVO, String srcAction, String destBillType,
								 String beDrivedActionName) throws BusinessException {

		RegapplyVO billvo = (RegapplyVO) srcBillVO.getParentVO();
		if (TRNConst.BUSITYPE_DIMISSION.equals(destBillType)) {
			// 推离职申请单时，转正结果为转正未通过
			if (billvo.getTrialresult() != null && TRNConst.TRIALRESULT_FALL == billvo.getTrialresult()) {
				return true;
			} else {
				return false;
			}
		} else {
			// 推其他时，转正结果为转正
			if (billvo.getTrialresult() != null && TRNConst.TRIALRESULT_PASS == billvo.getTrialresult()) {
				return true;
			} else {
				return false;
			}
		}
	}

	private boolean isExit(AggregatedValueObject[] retVOs, AggRegapplyVO billVO) throws BusinessException {
		for (int i = 0; retVOs != null && i < retVOs.length; i++) {
			if (billVO.getParentVO().getPrimaryKey().equals(retVOs[i].getParentVO().getPrimaryKey())) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 判断当前单据是否已上传附件
	 *
	 * @param bill
	 * @return
	 * @throws BusinessException
	 */
	private boolean isHasFile(RegapplyVO bill) throws BusinessException {
		if (bill.getIsneedfile() == null || !bill.getIsneedfile().booleanValue()) {
			// 不用必传附件
			return true;
		}

		IFileSystemService service = NCLocator.getInstance().lookup(IFileSystemService.class);
		NCFileNode node = service.getNCFileNodeTreeAndCreateAsNeed(bill.getPk_hi_regapply(), PubEnv.getPk_user());
		return hasFile(node);
	}

	private boolean isNull(Object o) {
		if (o == null || o.toString() == null || o.toString().trim().equals("")) {
			return true;
		}
		return false;
	}

	@Override
	public HashMap<String, Object> manualExecBills(AggRegapplyVO[] bills, LoginContext context, UFLiteralDate effectDate)
			throws BusinessException {
		if (!ArrayUtils.isEmpty(bills)) {
			for (int i = 0; i < bills.length; i++) {
				bills[i].getParentVO().setAttributeValue(RegapplyVO.REGULARDATE, effectDate);
			}
		}
		HashMap<String, Object> result = execBills(bills, context, true);
		// modify start: yunana 2013-5-10
		// 这个异常在在前台抛，避免超编通知NC消息发送之后回滚
		// String msg = (String) result.get(TRNConst.RESULT_MSG);
		// if (StringUtils.isNotBlank(msg))
		// {
		// throw new BusinessException(ResHelper.getString("6009tran", "06009tran0110")/* @res
		// "由于如下原因,部分单据没有执行成功:" */+ '\n' + msg);
		// }
		// modify end : yunana 2013-5-10
		return result;
	}

	public AggRegapplyVO[] queryByCondition(LoginContext context, String condition) throws BusinessException {
		AggRegapplyVO[] aggvos = queryByCondition(context, AggRegapplyVO.class, condition);
		if(aggvos != null && aggvos.length > 0) {
			for(AggRegapplyVO agg : aggvos) {
				Glbdef2VO[] glbdef1VOs = (Glbdef2VO[]) ServiceLocator.find(IPersistenceRetrieve.class).retrieveByClause(null, Glbdef2VO.class, "pk_hi_regapply ='"+agg.getParentVO().getPrimaryKey()+"' and nvl(dr,0) = 0");
				agg.setChildrenVO(glbdef1VOs);
			}
		}
		return aggvos;
	}

	public AggRegapplyVO queryByPk(String pk) throws BusinessException {
		AggRegapplyVO aggvo = queryByPk(AggRegapplyVO.class, pk);
//		Glbdef2VO[] glbdef1VOs = (Glbdef2VO[]) ServiceLocator.find(IPersistenceRetrieve.class).retrieveByClause(null, Glbdef2VO.class, "pk_hi_regapply ='"+pk+"' and nvl(dr,0) = 0");
//		aggvo.setChildrenVO(glbdef1VOs);
		return aggvo;
	}

	private void sendMessage(ValidateResultVO[] resultVOs) throws BusinessException {
		// 发送邮件
		for (ValidateResultVO vo : resultVOs) {
			if (StringUtils.isEmpty(vo.getHintMsg())) {
				continue;
			}
			OrgVO org = NCLocator.getInstance().lookup(IAOSQueryService.class).queryHROrgByOrgPK(vo.getPk_org());
			String hrorg = org == null ? vo.getPk_org() : org.getPk_org();
			IHRMessageSend messageSendService = NCLocator.getInstance().lookup(IHRMessageSend.class);
			// 组织消息VO
			HRBusiMessageVO messageInfoVO = new HRBusiMessageVO();

			// 设置业务函数
			Hashtable<String, Object> value = new Hashtable<String, Object>();
			value.put("reason", vo.getHintMsg());
			messageInfoVO.setBusiVarValues(value);

			messageInfoVO.setBillVO(vo);// 关联元数据实体VO
			String tempCode = "600301";// 超编通知消息模板源编码
			messageInfoVO.setMsgrescode(tempCode);// 消息源编码
			messageInfoVO.setPkorgs(new String[]{hrorg});
			// 发送消息
			messageSendService.sendBuziMessage_RequiresNew(messageInfoVO);
		}
	}

	@Override
	public AggregatedValueObject singleDirectApprove_RequiresNew(AggregatedValueObject aggvo, String pk_user, UFDateTime approveTime,
																 String approveNote, int blPassed) throws BusinessException {
		IFlowBizItf itf = NCObject.newInstance(aggvo).getBizInterface(IFlowBizItf.class);
		// 校验必输项
		if (blPassed == IPfRetCheckInfo.PASSING && IPfRetCheckInfo.COMMIT == itf.getApproveStatus()) {
			if (((RegapplyVO) aggvo.getParentVO()).getTrialresult() == null) {
				throw new BusinessException(ResHelper.getString("6009reg", "06009reg0030")/* @res "单据未填写试用结果" */);
			}
			if (StringUtils.isNotBlank(getMsg((RegapplyVO) aggvo.getParentVO()))) {
				throw new BusinessException(ResHelper.getString("6009reg", "06009reg0031")/*
				 * @res
				 * "单据中存在未填写的必输项"
				 */);
			}
		}
		changeBillData(itf, pk_user, approveTime, approveNote, blPassed);
		// 执行审批操作前，将审批信息写到pub_workflownote中
		WorkflownoteVO worknoteVO = buildWorkflownoteVO(itf, pk_user, approveNote, blPassed, itf.getBilltype());
		getIPersistenceUpdate().insertVO(null, worknoteVO, null);
		return getServiceTemplate().update(aggvo, false);
	}

	/**
	 * 更新单据
	 *
	 * @param <T>
	 * @param billvo
	 * @return
	 * @throws BusinessException
	 */
	@Override
	public <T extends AggregatedValueObject> T updateBill(T billvo, boolean blChangeAuditInfo) throws BusinessException {

		PfBusinessLock pfLock = null;
		IFlowBizItf flowItf = getFlowBizItf(billvo.getParentVO());
		try {
			// 加锁
			pfLock = new PfBusinessLock();
			pfLock.lock(new VOLockData(billvo, flowItf.getBilltype()), new VOConsistenceCheck(billvo, flowItf.getBilltype()));

			checkBillCodeRepeat(billvo);

			// 自定义校验器
			DefaultValidationService vService = new DefaultValidationService();
			createCustomValidators(vService, UPDATE);
			SuperVO[] headvos = getHeadVO(billvo).toArray(new SuperVO[0]);
			vService.validate(headvos);
			// 设置审计信息
			billvo.getParentVO().setStatus(VOStatus.UPDATED);
			setAuditInfoAndTs((SuperVO) billvo.getParentVO(), blChangeAuditInfo);
			Glbdef2VO[] glbdef1VO = (Glbdef2VO[]) billvo.getChildrenVO();
			billvo.setChildrenVO(null);
			String pk = getMDPersistenceService().saveBill(billvo);
			
			if(glbdef1VO != null && glbdef1VO.length > 0) {
				for(Glbdef2VO vo : glbdef1VO) {
					if(StringUtils.isNotBlank(vo.getPk_psndoc_sub())) {
						vo.setStatus(VOStatus.UPDATED);
					} else {
						vo.setPk_hi_regapply(pk);
						vo.setStatus(VOStatus.NEW);
					}
				}
				String[] pks = getMDPersistenceService().saveBill(glbdef1VO);
			}
			
			billvo.getParentVO().setPrimaryKey(pk);
		} catch (BillCodeRepeatBusinessException be) {
			String[] codes = be.getRepeatCodes();
			if (isAutoGenerateBillCode(TRNConst.BillTYPE_REG, PubEnv.getPk_group(), flowItf.getPkorg()) && codes != null) {
				for (int i = 0; i < codes.length; i++) {
					try {
						NCLocator.getInstance().lookup(IBillcodeManage.class)
								.AbandonBillCode_RequiresNew(TRNConst.BillTYPE_REG, PubEnv.getPk_group(), flowItf.getPkorg(), codes[i]);
					} catch (Exception e2) {
						Logger.error(e2.getMessage(), e2);
					}
				}
			}
			throw be;
		} catch (BusinessException e) {

			Logger.error(e.getMessage(), e);
			throw e;
		} finally {
			if (pfLock != null) {
				// 释放锁
				pfLock.unLock();
			}
		}
		T bill = (T) queryByPk(billvo.getParentVO().getPrimaryKey());
		billvo.getParentVO().setAttributeValue("ts", bill.getParentVO().getAttributeValue("ts"));
		return billvo;
	}

	/**
	 * 延长试用期限
	 */
	private void updateTrialForDelay(RegapplyVO vo) throws BusinessException {

		if (vo == null) {
			return;
		}
		// 取得当前有效的试用信息
		TrialVO[] trialVOs =
				(TrialVO[]) getIPersistenceRetrieve().retrieveByClause(null, TrialVO.class,
						"  endflag = 'N' and pk_psnorg ='" + vo.getPk_psnorg() + "' ");
		TrialVO trialVO = trialVOs[0];
		// 更新试用结果和计划转正日期
		String[] updateFields = {TrialVO.TRIALRESULT, TrialVO.ENDDATE};
		trialVO.setAttributeValue(updateFields[0], vo.getTrialresult());
		trialVO.setAttributeValue(updateFields[1], vo.getTrialdelaydate());
		getPersistenceUpdate().updateVO(null, trialVO, updateFields, null);
	}

	/**
	 * 转正
	 */
	private void updateTrialForFall(RegapplyVO vo) throws BusinessException {

		if (vo == null) {
			return;
		}
		// 取得当前有效的试用信息
		TrialVO[] trialVOs = getValidVO(TrialVO.class, vo.getPk_psnorg(), 1);
		// 更新有效的试用信息
		if (trialVOs != null && trialVOs.length > 0) {
			TrialVO trialVO = trialVOs[0];
			// 更新试用结果和计划转正日期
			trialVO.setTrialresult(vo.getTrialresult());
			trialVO.setEnddate(vo.getEnd_date());
			trialVO.setEndflag(UFBoolean.TRUE);
			// 转正单中的备注字段，需要同步到试用记录中 heqiaoa 20150609
			trialVO.setMemo(vo.getNewmemo());
			getServiceTemplate().update(trialVO, false);
		}
		// 更新工作记录的试用信息
		PsnJobVO jobVO = queryByPk(PsnJobVO.class, vo.getPk_psnjob());
		String[] updateFields = {PsnJobVO.TRIAL_FLAG, PsnJobVO.TRIAL_TYPE};
		jobVO.setAttributeValue(updateFields[0], false);
		jobVO.setAttributeValue(updateFields[1], null);
		getPersistenceUpdate().updateVO(null, jobVO, updateFields, null);
	}

	/**
	 * 转正
	 */
	private void updateTrialForPASS(RegapplyVO vo) throws BusinessException {

		if (vo == null) {
			return;
		}
		// 取得当前有效的试用信息
		TrialVO[] trialVOs = getValidVO(TrialVO.class, vo.getPk_psnorg(), 1);
		// 更新有效的试用信息
		if (trialVOs != null && trialVOs.length > 0) {
			TrialVO trialVO = trialVOs[0];
			// 更新试用结果和计划转正日期
			if (trialVO.getEnddate() == null) {
				trialVO.setEnddate(vo.getRegulardate());
			}
			trialVO.setTrialresult(vo.getTrialresult());
			trialVO.setEnddate(vo.getEnd_date());
			trialVO.setRegulardate(vo.getRegulardate());
			trialVO.setEndflag(UFBoolean.TRUE);
			// 转正单中的备注字段，需要同步到试用记录中 heqiaoa 20150609
			trialVO.setMemo(vo.getNewmemo());
			getServiceTemplate().update(trialVO, false);
		}
		// 4-2)新增一条工作记录
		PsnJobVO newVO = createNewPsnjob(vo);
		newVO =
				NCLocator.getInstance().lookup(IPersonRecordService.class)
						.addNewPsnjob(newVO, vo.getIfsynwork() == null ? false : vo.getIfsynwork().booleanValue(), vo.getPk_org());
	}

	/**
	 * 校验通过的单据信息
	 *
	 * @param vos
	 * @param context
	 * @return
	 * @throws BusinessException
	 */
	private void validate(AggRegapplyVO[] vos) throws BusinessException {
		String errMsg = "";
		for (AggRegapplyVO vo : vos) {
			RegapplyVO billvo = (RegapplyVO) vo.getParentVO();
			if (IPfRetCheckInfo.PASSING == billvo.getApprove_state()) {
				if (billvo.getTrialresult() == null) {
					errMsg += ResHelper.getString("6009reg", "06009reg0030")/* @res "单据未填写试用结果" */;
					continue;
				}
				if (StringUtils.isNotBlank(getMsg(billvo))) {
					errMsg += ResHelper.getString("6009reg", "06009reg0031")/* @res "单据中存在未填写的必输项" */;
					continue;
				}
			}
		}
		if (StringUtils.isNotBlank(errMsg)) {
			throw new BusinessException(errMsg);
		}
	}

	/**
	 * 获得编制校验通过的单据信息
	 *
	 * @param vos
	 * @param context
	 * @return
	 * @throws BusinessException
	 */
	public AggregatedValueObject[] validateBudget(AggregatedValueObject[] vos, LoginContext context) throws BusinessException {

		Vector<AggregatedValueObject> passVO = new Vector<AggregatedValueObject>();
		// 获取单据中人员数值
		PsnJobVO[] oldPsnJobVOs = new PsnJobVO[vos.length];
		PsnJobVO[] newPsnJobVOs = new PsnJobVO[vos.length];
		for (int i = 0; i < vos.length; i++) {
			SuperVO bill = (SuperVO) vos[i].getParentVO();
			PsnJobVO psn =
					(PsnJobVO) NCLocator.getInstance().lookup(IPersistenceRetrieve.class)
							.retrieveByPk(null, PsnJobVO.class, (String) bill.getAttributeValue(RegapplyVO.PK_PSNJOB));
			// 转正前人员信息
			oldPsnJobVOs[i] = (PsnJobVO) psn.clone();
			// 转正后人员信息
			String[] codes =
					{
							RegapplyVO.NEWPK_JOB,
							RegapplyVO.NEWPK_JOB_TYPE,
							RegapplyVO.NEWPK_JOBGRADE,
							RegapplyVO.NEWPK_JOBRANK,
							RegapplyVO.NEWPK_POST,
							RegapplyVO.NEWPK_POSTSERIES};
			for (String name : bill.getAttributeNames()) {
				if (name.startsWith("new")) {
					Object value = bill.getAttributeValue(name);
					if (value == null && !ArrayUtils.contains(codes, name)) {
						value = psn.getAttributeValue(name.substring(3));
					}
					psn.setAttributeValue(name.substring(3), value);
				}
			}
			psn.setAttributeValue(PsnJobVO.PK_PSNJOB, "");
			newPsnJobVOs[i] = psn;
			passVO.add(vos[i]);
		}
		// 编制校验
		ValidateResultVO[] resultVOs =
				NCLocator.getInstance().lookup(IOrgBudgetQueryService.class)
						.validateBudgetValue_RequiresNew(context, oldPsnJobVOs, newPsnJobVOs);
		// 编制校验全部通过
		if (resultVOs == null || resultVOs.length == 0) {
			return vos;
		}
		// modify start: 2013-5-10 yunana
		// 发送通知，改用平台方法发送通知
		sendMessage(resultVOs);
		// modify end: 2013-5-10 yunana

		for (ValidateResultVO resultVO : resultVOs) {
			// 校验未通过,即超编且强制控制的单据
			if (!resultVO.isValid()) {
				String pk_org = resultVO.getPk_org();
				// 排除编制校验未通过的组织单据
				for (AggregatedValueObject vo : vos) {
					if (pk_org.equals(vo.getParentVO().getAttributeValue(RegapplyVO.NEWPK_ORG))) {
						passVO.removeElement(vo);
					}
				}
			}
		}
		return passVO.toArray(new AggregatedValueObject[0]);
	}

	/**
	 * 校验不严格控制的编制
	 *
	 * @param context
	 * @param billvos
	 * @return
	 * @throws BusinessException
	 */
	public String validateValidBudget(LoginContext context, AggregatedValueObject[] billvos) throws BusinessException {
		// 前台已经进行了审批即执行的过滤,所以这里的billvos都是需要执行的
		PsnJobVO[] oldPsnJobVOs = new PsnJobVO[billvos.length];
		PsnJobVO[] newPsnJobVOs = new PsnJobVO[billvos.length];

		for (int i = 0; i < billvos.length; i++) {
			SuperVO bill = (SuperVO) billvos[i].getParentVO();
			PsnJobVO psn =
					(PsnJobVO) NCLocator.getInstance().lookup(IPersistenceRetrieve.class)
							.retrieveByPk(null, PsnJobVO.class, (String) bill.getAttributeValue(RegapplyVO.PK_PSNJOB));
			// 转正前人员信息
			oldPsnJobVOs[i] = (PsnJobVO) psn.clone();
			// 转正后人员信息
			String[] codes =
					{
							RegapplyVO.NEWPK_JOB,
							RegapplyVO.NEWPK_JOB_TYPE,
							RegapplyVO.NEWPK_JOBGRADE,
							RegapplyVO.NEWPK_JOBRANK,
							RegapplyVO.NEWPK_POST,
							RegapplyVO.NEWPK_POSTSERIES};
			for (String name : bill.getAttributeNames()) {
				if (name.startsWith("new")) {
					Object value = bill.getAttributeValue(name);
					if (value == null && !ArrayUtils.contains(codes, name)) {
						value = psn.getAttributeValue(name.substring(3));
					}
					psn.setAttributeValue(name.substring(3), value);
				}
			}
			newPsnJobVOs[i] = psn;
			newPsnJobVOs[i].setPk_psnjob("");
		}
		ValidateResultVO[] resultVOs = null;
		if (oldPsnJobVOs.length != 0 && oldPsnJobVOs.length != 0) {
			// 编制校验
			resultVOs =
					NCLocator.getInstance().lookup(IOrgBudgetQueryService.class).validateBudgetValue(context, oldPsnJobVOs, newPsnJobVOs);
		}

		String strWarningMsg = "";

		if (resultVOs != null) {
			for (ValidateResultVO resultVO : resultVOs) {
				// 只对不严格控制的进行校验
				if (resultVO.getHintMsg() != null && resultVO.isValid()) {
					strWarningMsg += "\n" + resultVO.getHintMsg();
				} else if (resultVO.getHintMsg() != null) {
					throw new BusinessException(resultVO.getHintMsg());
				}

			}
		}
		return strWarningMsg;

	}

	/**
	 * 保存并且提交(手机端)
	 */
	@Override
	public Map saveAndCommit(AggRegapplyVO billvo, String actionCode, String billType, LoginContext context) throws BusinessException {

		boolean isAutoGenerateBillCode = isAutoGenerateBillCode(TRNConst.BillTYPE_REG, context.getPk_group(), context.getPk_org());

		AggRegapplyVO agg = saveBill(billvo, isAutoGenerateBillCode);

		return commitBill(billvo, actionCode, billType, isAutoGenerateBillCode, agg);
	}

	@Override
	public AggRegapplyVO saveBill(AggRegapplyVO billvo, boolean isAutoGenerateBillCode) throws BusinessException {
		BillCodeHelper.unlockBillCodeRule("hr_auto_billcode" + TRNConst.BillTYPE_REG);
		if (!isAutoGenerateBillCode && StringUtils.isBlank(((RegapplyVO) billvo.getParentVO()).getPk_hi_regapply())) {
			// 如果不自动生成编码,则对编码规则进行加锁
			BillCodeHelper.lockBillCodeRule("hr_auto_billcode" + TRNConst.BillTYPE_REG, 100);
			String prefix = "ZD" + TRNConst.BillTYPE_REG + PubEnv.getServerDate().toStdString();
			// 不自动生成单据号 /默认规则生成 "单据类型+yyyy-mm-dd+_流水号"
			String flowCode = SQLHelper.getFlowCode(prefix, RegapplyVO.BILL_CODE, RegapplyVO.class);
			// 不自动生成单据号
			((RegapplyVO) billvo.getParentVO()).setBill_code(prefix + "_" + getFlowCode(flowCode, 0));
		}
		AggRegapplyVO agg = null;
		PfProcessBatchRetObject validateRetObj = null;
		// 保存数据
		try {
			if (StringUtils.isBlank(((RegapplyVO) billvo.getParentVO()).getPk_hi_regapply())) {
				agg = this.insertBill(billvo);
			} else {
				agg = this.updateBill(billvo, true);
			}
		} catch (Exception e1) {
			if (!isAutoGenerateBillCode && StringUtils.isBlank(((RegapplyVO) billvo.getParentVO()).getPk_hi_regapply())) {
// 如在保存过程中遇到异常，则解锁编码
				BillCodeHelper.unlockBillCodeRule("hr_auto_billcode" + TRNConst.BillTYPE_REG);
			}
			throw new BusinessException(e1.getMessage());
		}
		return agg;
	}

	@Override
	public Map commitBill(AggRegapplyVO billvo, String actionCode, String billType, boolean isAutoGenerateBillCode, AggRegapplyVO agg) throws BusinessException {
		PfProcessBatchRetObject validateRetObj;
		agg = queryByPk(agg.getParentVO().getPrimaryKey());
		// 提交前校验
		AggRegapplyVO[] billvoArr = new AggRegapplyVO[]{agg};
		validateRetObj = NCLocator.getInstance().lookup(IHrPf.class).submitValidation(null, null, null, 1, agg);
		if (validateRetObj == null) {
			if (!isAutoGenerateBillCode && StringUtils.isBlank(((RegapplyVO) billvo.getParentVO()).getPk_hi_regapply())) {
				// 如在保存过程中遇到异常，则解锁编码
				BillCodeHelper.unlockBillCodeRule("hr_auto_billcode" + TRNConst.BillTYPE_REG);
			}
			throw new BusinessException("data error！");
		}
		if (validateRetObj.getRetObj() == null || validateRetObj.getRetObj().length == 0) {
			if (!isAutoGenerateBillCode) {
				// 如在保存过程中遇到异常，则解锁编码
				BillCodeHelper.unlockBillCodeRule("hr_auto_billcode" + TRNConst.BillTYPE_REG);
			}
			// 状态校验都没有通过
			String errStr = validateRetObj.getExceptionMsg();
			if (StringUtils.isEmpty(errStr)) {
				throw new BusinessException("data error！");
			}
			throw new ValidationException(errStr);
		}
		AggregatedValueObject[] passObjs = null;
		if (validateRetObj.getRetObj() != null && validateRetObj.getRetObj().length > 0) {
			passObjs = (AggregatedValueObject[]) validateRetObj.getRetObj();
		}
		Map retMap = new HashMap<String, Object>();
		String message = "";
		try {
			CloudPFlowContext flowContext = new CloudPFlowContext();
			flowContext.setActionName(actionCode);
			flowContext.setBillType(billType);
			flowContext.setBillVos(passObjs);
			HashMap<Object, Object> eParam = new HashMap<Object, Object>();
			flowContext.seteParam(eParam);
			ICloudScriptPFlowService service = NCLocator.getInstance().lookup(ICloudScriptPFlowService.class);
			Object[] objs = service.exeScriptPFlow(flowContext);
			Object obj = objs[0];
			if (obj instanceof Map && ((Map<?, ?>) obj).get(PfUtilBaseTools.PARAM_WORKFLOWTYPE) != null
					&& (PfUtilBaseTools.PARAM_APPROVEFLOW.equals(String.valueOf(((Map<?, ?>) obj).get(PfUtilBaseTools.PARAM_WORKFLOWTYPE))))) {
				Map<String, Object> map = (Map<String, Object>) obj;
				retMap.put("agg", agg);
				retMap.put("content", map);
				return retMap;
			}
		} catch (Exception e) {
			Logger.error(message, e);
			message = e.getMessage();
			if (message == null && e.getCause() != null) {
				message = e.getCause().getMessage();
				if (message == null && e.getCause().getCause() != null) {
					message = e.getCause().getCause().getMessage();
					if (message == null && e.getCause().getCause().getCause() != null) {
						message = e.getCause().getCause().getCause().getMessage();
					}
				}
			}
		} finally {
			if (!isAutoGenerateBillCode) {
				// 如果不自动生成编码,则对编码规则进行加锁
				BillCodeHelper.unlockBillCodeRule("hr_auto_billcode" + TRNConst.BillTYPE_REG);
			}
		}
		String errMsg = "";
		String msg1 = validateRetObj == null ? null : validateRetObj.getExceptionMsg();
		String msg2 = message;
		if ((StringUtils.isNotBlank(msg1)) || (StringUtils.isNotBlank(msg2))) {
			errMsg = new StringBuilder().append((StringUtils.isBlank(msg1)) ? "" : msg1).append('\n').append((StringUtils.isBlank(msg2)) ? "" : msg2).toString();
		}
		if (StringUtils.isNotBlank(errMsg)) {
			// 返回提交后状态为提交的数据
			throw new BusinessException(errMsg);
		}

		retMap.put("agg", agg);
		return retMap;
	}

}
