package nc.impl.fa.alter;

import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.MethodUtils;

import nc.bs.am.framework.action.ActionContext;
import nc.bs.am.framework.action.IActionTemplate;
import nc.bs.am.framework.action.IRule;
import nc.bs.am.framework.action.approve.ApproveActionTemplate;
import nc.bs.am.framework.action.approve.UnApproveActionTemplate;
import nc.bs.am.framework.common.rule.ValidateServiceRule;
import nc.bs.am.framework.constant.rule.RuleConst;
import nc.bs.dao.BaseDAO;
import nc.bs.dao.DAOException;
import nc.bs.framework.common.InvocationInfoProxy;
import nc.bs.framework.common.NCLocator;
import nc.bs.uif2.validation.Validator;
import nc.impl.am.bill.BillBaseDAO;
import nc.impl.am.bill.rule.BillCodeInsertAfterRule;
import nc.impl.am.bill.rule.BillCodeInsertBeforeRule;
import nc.impl.am.bill.rule.BillCodeUpdateRule;
import nc.impl.am.bill.rule.VOSagasStatusCheckBeforeRule;
import nc.impl.am.common.InSqlManager;
import nc.impl.am.common.PfUtilToolsAM;
import nc.impl.am.db.DBAccessUtil;
import nc.impl.am.db.QueryUtil;
import nc.impl.am.db.VOPersistUtil;
import nc.impl.am.db.processor.BeanListMapProcessor;
import nc.impl.am.db.processor.BooleanProcessor;
import nc.impl.am.db.processor.ColumnSetProcessor;
import nc.impl.fa.alter.rule.AlterBillCodeDeleteRule;
import nc.impl.fa.alter.rule.AlterCategoryCheckRule;
import nc.impl.fa.alter.rule.AlterDealValueAfterRule;
import nc.impl.fa.alter.rule.AlterDeleteFipAfterRule;
import nc.impl.fa.alter.rule.AlterPushTraceAfterRule;
import nc.impl.fa.alter.rule.AlterSendFipAfterRule;
import nc.impl.fa.alter.rule.AlterStorageBillVORule;
import nc.impl.fa.alter.rule.AlterUpdateDepLogAfterRule;
import nc.impl.fa.alter.rule.AlterWriteBackToCardAfterRule;
import nc.impl.fa.alter.rule.SendARCAlterRule;
import nc.impl.fa.alter.rule.UpdateBillStatusOfWorkFlowAfterRule;
import nc.impl.fa.alter.trace.TraceManager;
import nc.impl.fa.alter.validator.AlterCapitalUnapproveValidator;
import nc.impl.fa.alter.validator.AlterCheckCardLegalValidator;
import nc.impl.fa.alter.validator.AlterSrcBillLegalValidator;
import nc.impl.fa.common.pf.PfUtilToolsFA;
import nc.impl.fa.common.rule.CreateBillLogAfterRule;
import nc.impl.fa.common.rule.DeleteBillLogAfterRule;
import nc.impl.fa.common.rule.UpdateCardLogAfterRule;
import nc.impl.fa.common.validator.CheckCardLegalValidator;
import nc.impl.fa.common.validator.CheckHasFipMakeVoucherForAccbooks;
import nc.impl.fa.common.validator.CheckMinUnClosedBookPeriodValidator;
import nc.impl.fa.rule.AssetCodeIsSameCheckRule;
import nc.impl.fa.rule.FAAccbookCheckSealRule;
import nc.impl.fa.rule.PKAccbookBeforeRule;
import nc.impl.fa.rule.ReceiptScanBeforeRule;
import nc.impl.fa.rule.SrcMessageExistValidator;
import nc.impl.fa.rule.UpdateSrcMsgState4BillAfterRule;
import nc.itf.aim.pub.IEquipToFaService;
import nc.itf.am.pub.ILocationService;
import nc.itf.fa.byzlog.IbyzLogRcord;
import nc.itf.fa.prv.IAlter;
import nc.itf.fa.service.IAccbookInfoService;
import nc.itf.fa.service.IAssetService;
import nc.itf.fa.service.ILogService;
import nc.itf.fa.service.IReduceService;
import nc.itf.fa.service.IUseDeptScaleService;
import nc.itf.org.IOrgConst;
import nc.itf.pca.domain.cvtfixedasset.ICostToFixedBillQuery;
import nc.jdbc.framework.SQLParameter;
import nc.jdbc.framework.processor.ColumnListProcessor;
import nc.jdbc.framework.processor.ResultSetProcessor;
import nc.pub.am.common.validator.SrcBillUnApproveValidator;
import nc.pub.billcode.IBCRConst;
import nc.pub.billcode.itf.IBillcodeManage;
import nc.pub.billcode.vo.BillCodeContext;
import nc.pub.fa.alter.trace.TraceResultVO;
import nc.pub.fa.alter.trace.TraceVO;
import nc.pub.fa.card.AssetFieldConst;
import nc.pub.fa.card.AssetStateConst;
import nc.pub.fa.common.consts.FlagConsts;
import nc.pub.fa.common.consts.LogTypeConst;
import nc.pub.fa.common.manager.DeptScaleManager;
import nc.pub.fa.common.manager.VOManager;
import nc.pub.fa.common.util.FAScaleUtils;
import nc.pub.fa.common.util.FAUseDeptKeyGenerator;
import nc.pub.fa.common.util.StringUtils;
import nc.pub.fa.common.util.UseDeptScaleUtils;
import nc.pub.fa.msg.MsgManager;
import nc.pub.fa.msg.MsgVO;
import nc.pubitf.org.IAccountingBookPubService;
import nc.pubitf.org.IDeptPubService;
import nc.pubitf.org.IOrgRelationDataPubService;
import nc.vo.aim.equip.EquipHeadVO;
import nc.vo.am.addreducestyle.AddreduceStyleVO;
import nc.vo.am.common.AMSuperVO;
import nc.vo.am.common.BaseLockData;
import nc.vo.am.common.BizContext;
import nc.vo.am.common.TransportBillVO;
import nc.vo.am.common.util.ArrayUtils;
import nc.vo.am.common.util.BaseVOUtils;
import nc.vo.am.common.util.BillTransportTool;
import nc.vo.am.common.util.CloneUtil;
import nc.vo.am.common.util.CollectionUtils;
import nc.vo.am.common.util.ExceptionUtils;
import nc.vo.am.common.util.MapUtils;
import nc.vo.am.common.util.MultiLanguageUtil;
import nc.vo.am.common.util.OrgUtils;
import nc.vo.am.common.util.UFDoubleUtils;
import nc.vo.am.constant.BillStatusConst;
import nc.vo.am.constant.BillTypeConst_4A;
import nc.vo.am.constant.BillTypeConst_4B;
import nc.vo.am.constant.BillTypeConst_FA;
import nc.vo.am.constant.BillTypeOther;
import nc.vo.am.constant.CommonKeyConst;
import nc.vo.am.constant.IWorkOrderFields;
import nc.vo.am.manager.AccbookManager;
import nc.vo.am.manager.AccperiodVO;
import nc.vo.am.manager.CurrencyRateManager;
import nc.vo.am.manager.LockManager;
import nc.vo.am.manager.PeriodManager;
import nc.vo.am.proxy.AMProxy;
import nc.vo.fa.accbookinfo.AccbookHeadVO;
import nc.vo.fa.accbookinfo.ConvertData;
import nc.vo.fa.alter.AlterBodyVO;
import nc.vo.fa.alter.AlterHeadVO;
import nc.vo.fa.alter.AlterSheetVO;
import nc.vo.fa.alter.AlterVO;
import nc.vo.fa.alter.helper.AlterKeyConst;
import nc.vo.fa.alter.helper.AlterTransiTypeConst;
import nc.vo.fa.asset.AssetVO;
import nc.vo.fa.byzLogVO.ByzLogRcordVO;
import nc.vo.fa.deptscale.DeptScaleVO;
import nc.vo.logging.Debug;
import nc.vo.org.AccountingBookVO;
import nc.vo.org.DeptVO;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.BusinessException;
import nc.vo.pub.SuperVO;
import nc.vo.pub.VOStatus;
import nc.vo.pub.compiler.PfParameterVO;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDate;
import nc.vo.pub.lang.UFDouble;
import nc.vo.uif2.LoginContext;
import nc.vo.util.AuditInfoUtil;
import nccloud.commons.lang.builder.EqualsBuilder;

/**
 * 变动单后台实现类
 * 
 * @author weizq
 */
public class AlterImpl extends BillBaseDAO<AlterVO> implements IAlter {

	private DBAccessUtil dbAccessUtil = new DBAccessUtil();

	/*
	 * 前台调用的方法，返回界面时，进行流量处理
	 * 
	 * @date 2010-5-26
	 */
	@Override
	public TransportBillVO insert(LoginContext context, AlterVO billVO, List<String> showAlterKeyList)
			throws BusinessException {
		AlterHeadVO headVO = (AlterHeadVO) billVO.getParentVO();
		String pk_accbook = headVO.getPk_accbook();
		// 资产变动，存在财务字段，但表头无资产账簿，审批报错（表体主键信息错误），请加上校验，提示用户配置资产账簿
		for (String alterItem : showAlterKeyList) {
			List<String> finance_fieldList = Arrays.asList(AssetFieldConst.ACCOUNT_FIELD); // 卡片上所有财务字段
			if (finance_fieldList.contains(alterItem) && null == pk_accbook) {
				ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
						"02012010-0086")/* @res "变动项目中包含财务字段，请将表头的【资产账簿】字段显示出来！\n" */
				);
			}
		}

		// 调用不进行流量处理的方法
		billVO = insertAlterVO(context, billVO, showAlterKeyList);

		// 流量处理。转化VO，只传送界面不存在的字段,pk,ts,creator...
		TransportBillVO transportBillVO = BillTransportTool.createTransportBill(billVO, BillTransportTool.MODE_INSERT);

		return transportBillVO;
	}

	/**
	 * 后台新增保存的方法，不考虑流量
	 * 
	 * @param context
	 * @param billVO
	 * @return
	 * @throws BusinessException
	 * @date 2010-5-26
	 */
	protected AlterVO insertAlterVO(LoginContext context, AlterVO billVO, List<String> showAlterKeyList)
			throws BusinessException {

		// 变动项目不能为空
		if (CollectionUtils.isEmpty(showAlterKeyList)) {
			throw new IllegalArgumentException(" showAlterKeyList can't be Empty!");
		}

		// 校验
		validateAlterData(billVO, showAlterKeyList);

		// 处理多币种
		dealMultiCurrency(billVO);

		AlterVO retAlterVO = ArrayUtils.getFirstElem(super.insertBillVO(billVO));

		// 保存明细数据
		AlterSheetVO[] sheetVOs = AlterHelper.generaterSheetVOs(retAlterVO, showAlterKeyList);
		VOPersistUtil.insert(sheetVOs);

		// 不能使用finally块进行:因为保存报错了，前台依然处于编辑状态，应该由取消按钮来解锁 或者 保存成功了解锁。
		releasePKCardLock(billVO);

		return retAlterVO;
	}

	/**
	 * 
	 * 新增保存和修改保存校验
	 * <p>
	 * <b>examples:</b>
	 * <p>
	 * 使用示例
	 * <p>
	 * <b>参数说明</b>
	 * 
	 * @param billVO
	 * @param showAlterKeyList
	 *                         <p>
	 * @author weizq
	 * @throws BusinessException
	 * @time 2011-4-1 下午03:18:04
	 */
	private void validateAlterData(AlterVO billVO, List<String> showAlterKeyList) throws BusinessException {

		// 1. 校验账簿
		checkAccbook(billVO, showAlterKeyList);

		// 2. 校验原币原值变动单中的原值合法性，如果本币原值来源于原币原值
		checkOrginvalueLocalValue(billVO);

		// 3. 校验变动后资产类别是否跟变动前资产类别(包括父类别)关联相同账簿
		checkCategory(billVO, showAlterKeyList);

		// 4. 校验资产追溯只能在一个期间做一次
		checkTraceOnceCard(billVO);

		// 5. 校验资产编码是否一致
		checkAssetCode(billVO, showAlterKeyList);
	}

	/**
	 * 校验资产编码唯一性
	 * <p>
	 * 
	 * @author weizq
	 * @throws BusinessException
	 * @time 2011-11-11 上午10:31:33
	 */
	private void checkAssetCode(AlterVO billVO, List<String> showAlterKeyList) throws BusinessException {

		// 变动前变动后不一样的资产编码
		List<String> notEqualAfterAssetCodes = new ArrayList<String>();

		AlterHeadVO headVO = (AlterHeadVO) billVO.getParentVO();
		if (showAlterKeyList.contains(AssetFieldConst.ASSET_CODE)) {
			AlterBodyVO[] bodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();
			if (bodyVOs == null || bodyVOs.length == 0) {
				return;
			}
			for (AlterBodyVO bodyVO : bodyVOs) {
				// 删除态的表体不需要校验
				if (VOStatus.DELETED != bodyVO.getStatus()) {
					String beforeAssetCode = (String) bodyVO
							.getAttributeValue(AssetFieldConst.ASSET_CODE + AlterKeyConst.BEFORE_SUFFIX);
					String afterAssetCode = (String) bodyVO
							.getAttributeValue(AssetFieldConst.ASSET_CODE + AlterKeyConst.AFTER_SUFFIX);
					if (!beforeAssetCode.equals(afterAssetCode)) {
						notEqualAfterAssetCodes.add(afterAssetCode);
					}
				}
			}

			String pk_group = InvocationInfoProxy.getInstance().getGroupId();
			String pk_org = headVO.getPk_org();
			// 获取设置的编码信息
			BillCodeContext billCodeContext = AMProxy.lookup(IBillcodeManage.class)
					.getBillCodeContext(AssetFieldConst.ASSET_CODE, pk_group, pk_org);

			// 相同的资产编码
			String[] sameCodes = getSameCode(billCodeContext, AssetFieldConst.ASSET_CODE,
					notEqualAfterAssetCodes.toArray(new String[0]), pk_org);

			if (sameCodes != null && sameCodes.length != 0) {
				String msg = StringUtils.getInSqlStringByArray(sameCodes);

				String message = nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0", "02012010-0076", null,
						new String[] { msg })/*
												 * @res "变动后资产编码[{0}]重复。 \n"
												 */;
				ExceptionUtils.asBusinessException(message);
			}
		}
	}

	/**
	 * 查询重复的号。
	 * 
	 * @param billCodeContext
	 * @param field
	 * @param codes
	 * @param pk_org
	 * @return
	 * @throws BusinessException
	 */
	private String[] getSameCode(BillCodeContext billCodeContext, String field, String[] codes, String pk_org)
			throws BusinessException {

		if (ArrayUtils.isNotEmpty(codes)) {
			String pk_group = InvocationInfoProxy.getInstance().getGroupId();
			if (billCodeContext != null) {
				// 批量的时候，都是
				StringBuffer sql = new StringBuffer();
				sql.append("select");
				sql.append(" " + field);
				sql.append(" from fa_card");
				sql.append(" where ");
				sql.append(field);
				sql.append(" in" + InSqlManager.getInSQLValue(codes));
				// 按照编码规则中的编码范围去判断唯一性。
				if (billCodeContext.getUniquescope().equals(IBCRConst.UNIQUE_GRP)) {
					sql.append(" and pk_group = '" + pk_group + "'");
				} else if (billCodeContext.getUniquescope().equals(IBCRConst.UNIQUE_ORG)) {
					sql.append(" and pk_org = '" + pk_org + "'");
				}
				sql.append(" and dr = 0");
				Set<String> sameCodes = new DBAccessUtil().executeQuery(sql.toString(),
						new ColumnSetProcessor<String>());
				if (sameCodes != null && sameCodes.size() > 0) {
					return CollectionUtils.toArray(sameCodes);
				}
			} else {
				ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("facard_0",
						"02012005-0383")/* @res "资产编码编码规则定义没有设置" */);
			}
		}
		return null;
	}

	/**
	 * 
	 * 校验资产追溯只能在一个期间做一次
	 * <p>
	 * <b>examples:</b>
	 * <p>
	 * 使用示例
	 * <p>
	 * <b>参数说明</b>
	 * 
	 * @param billVO
	 *               <p>
	 * @author weizq
	 * @throws BusinessException
	 * @time 2011-6-27 下午07:26:07
	 */
	private void checkTraceOnceCard(AlterVO billVO) throws BusinessException {

		String trace_type = (String) billVO.getParentVO().getAttributeValue(AlterHeadVO.TRANSI_TYPE);
		if (AlterTransiTypeConst.ASSET_TRACE.equals(trace_type)) {
			String pk_alter = billVO.getParent().getPrimaryKey();
			String pk_accbook = (String) billVO.getParentVO().getAttributeValue(AlterHeadVO.PK_ACCBOOK);
			UFDate bizDate = (UFDate) billVO.getParentVO().getAttributeValue(AlterHeadVO.BUSINESS_DATE);
			Set<String> resultSet = queryMadeAlterTrace(pk_alter, pk_accbook, bizDate);
			List<String> cards = new ArrayList<String>();
			AlterBodyVO[] bodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();
			if (bodyVOs == null) {
				return;
			}

			for (AlterBodyVO bodyVO : bodyVOs) {
				// 只有新增才需要去判断
				if (bodyVO.getStatus() == VOStatus.NEW) {
					cards.add(bodyVO.getPk_card());
				}
			}

			if (cards.size() == 0) {
				return;
			}

			List<String> doTraceCards = new ArrayList<String>();

			// 过滤掉做了资产追溯的卡片PK
			for (String value : cards) {
				if (resultSet.contains(value)) {
					doTraceCards.add(value);
				}
			}

			if (doTraceCards.size() != 0) {
				Map<String, String> cardCodes = AMProxy.lookup(IAssetService.class)
						.gainCard_code(doTraceCards.toArray(new String[0]));
				String errorMsg = nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0", "02012010-0060",
						null, new String[] { StringUtils.getInSqlStringByArray(cardCodes.values()
								.toArray(new String[0])) })/*
															 * @res "卡片编号为{0}的卡片在此期间已做过资产追溯, 请重新选择卡片。 \n"
															 */;
				ExceptionUtils.asBusinessException(errorMsg);
			}
		}
	}

	/**
	 * 
	 * 校验变动后资产类别是否跟变动前资产类别(包括父类别)关联相同账簿
	 * <p>
	 * <b>examples:</b>
	 * <p>
	 * 使用示例
	 * <p>
	 * <b>参数说明</b>
	 * 
	 * @param billVO
	 * @param showAlterKeyList
	 *                         <p>
	 * @author weizq
	 * @throws BusinessException
	 * @time 2011-4-1 下午03:20:17
	 */
	private void checkCategory(AlterVO billVO, List<String> showAlterKeyList) throws BusinessException {

		// 只有资产类别变动才进行判断
		if (showAlterKeyList.contains(AlterKeyConst.PK_CATEGORY)) {
			// 变动前类别
			List<String> before_categorys = new ArrayList<String>();
			// 变动后类别
			List<String> after_categorys = new ArrayList<String>();

			AlterBodyVO[] bodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();
			// 只有点修改直接点保存，会穿过来时空
			if (ArrayUtils.isEmpty(bodyVOs)) {
				return;
			}

			// 将表体卡片中的类别赋值到before_categorys和after_categorys
			for (AlterBodyVO bodyVO : bodyVOs) {
				// 只有新增或者是修改才判断
				if (bodyVO.getStatus() == VOStatus.NEW || bodyVO.getStatus() == VOStatus.UPDATED) {
					String before_category = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_CATEGORY_BEFORE);
					String after_category = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_CATEGORY_AFTER);
					if (!before_categorys.contains(before_category)) {
						before_categorys.add(before_category);
					}
					if (!after_categorys.contains(after_category)) {
						after_categorys.add(after_category);
					}
				}
			}

			before_categorys.addAll(after_categorys);

			if (before_categorys.size() == 0) {
				return;
			}

			// 错误提示
			StringBuffer errorMsg = new StringBuffer();

			String pk_org = ((AlterHeadVO) billVO.getParentVO()).getPk_org();
			UFDate business_date = ((AlterHeadVO) billVO.getParentVO()).getBusiness_date();

			// 查询组织启用的账簿
			AccountingBookVO[] accounting = AMProxy.lookup(IAccountingBookPubService.class)
					.queryAccountingBookByFinanceOrgIDAndDate(pk_org, business_date.toString());

			if (accounting == null || accounting.length == 0) {
				errorMsg.append(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
						"02012010-0061")/*
										 * @ res " 组织没有关联账簿，请检查 \n "
										 */);
				ExceptionUtils.asBusinessException(errorMsg.toString());
			}

			List<String> accbooks = new ArrayList<String>();
			for (int i = 0; i < accounting.length; i++) {
				accbooks.add(accounting[i].getPk_accountingbook());
			}

			// 类别对应的账簿
			Map<String, List<String>> categorySetBooks = AMProxy.lookup(IAccbookInfoService.class)
					.queryAccbookWithQueryCategory(pk_org, accbooks.toArray(new String[0]),
							before_categorys.toArray(new String[0]));

			categorySetBooks = getCategoryWithAccbook(categorySetBooks);

			for (int i = 0; i < bodyVOs.length; i++) {
				AlterBodyVO bodyVO = bodyVOs[i];
				if (bodyVO.getStatus() == VOStatus.NEW || bodyVO.getStatus() == VOStatus.UPDATED) {
					String before_category = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_CATEGORY_BEFORE);
					String after_category = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_CATEGORY_AFTER);
					List<String> beforeAccbooks = categorySetBooks.get(before_category);
					List<String> afterAccbooks = categorySetBooks.get(after_category);
					if (CollectionUtils.isEmpty(afterAccbooks) || beforeAccbooks.size() != afterAccbooks.size()) {
						errorMsg.append(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
								"02012010-0062", null,
								new String[] { String.valueOf(i + 1) })/*
																		 * @ res "表体第{0}行中变动前后的类别关联账簿不同，不能做类别调整单。 \n"
																		 */);
					} else if (afterAccbooks.size() != 0) {
						// 如果不等，则给出提示
						for (String pk_accbook : afterAccbooks) {
							if (!beforeAccbooks.contains(pk_accbook)) {
								errorMsg.append(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
										"02012010-0062", null, new String[] {
												String.valueOf(i + 1) })/*
																		 * @ res "表体第{0}行中变动前后的类别关联账簿不同，不能做类别调整单。 \n"
																		 */);
							}
						}
					}
				}
			}

			if (errorMsg.length() != 0) {
				ExceptionUtils.asBusinessException(errorMsg.toString());
			}
		}
	}

	/**
	 * 得到资产类别关联的账簿
	 * 
	 * @param accbookDataMap Map<账簿, List<资产类别>>
	 * @return Map<资产类别,Set<账簿>>
	 */
	private Map<String, List<String>> getCategoryWithAccbook(Map<String, List<String>> accbookDataMap) {

		// 把资产类别和账簿的<键，值>进行互换
		Map<String, List<String>> returnData = new HashMap<String, List<String>>();
		for (String pk_accbook : accbookDataMap.keySet()) {
			List<String> queryCategory = accbookDataMap.get(pk_accbook);
			if (queryCategory != null && queryCategory.size() > 0) {
				for (String pk_category : queryCategory) {
					if (returnData.containsKey(pk_category)) {
						returnData.get(pk_category).add(pk_accbook);
					} else {
						List<String> accbookset = new ArrayList<String>();
						accbookset.add(pk_accbook);
						returnData.put(pk_category, accbookset);
					}
				}
			}
		}

		return returnData;
	}

	/**
	 * 校验原币原值变动单中的原值合法性，如果本币原值来源于原币原值
	 * <p>
	 * 
	 * @author weizq
	 * @throws BusinessException
	 * @time 2011-3-4 下午01:25:50
	 */
	private void checkOrginvalueLocalValue(AlterVO billVO) throws BusinessException {

		AlterHeadVO headVO = (AlterHeadVO) billVO.getParent();
		String transi_type = headVO.getTransi_type();

		// <pk_card, BodyVO>
		Map<String, AlterBodyVO> cardBodyVO = new HashMap<String, AlterBodyVO>();
		// 只有修改直接点保存，会传过来为空的.
		if (ArrayUtils.isEmpty(billVO.getChildrenVO())) {
			return;
		}
		for (AlterBodyVO bodyVO : (AlterBodyVO[]) billVO.getChildrenVO()) {
			cardBodyVO.put(bodyVO.getPk_card(), bodyVO);
		}
//		ByzLogRcordVO logvo = new ByzLogRcordVO();
		String[] pk_cards = VOManager.getAttributeValueArray(billVO.getChildrenVO(), AlterBodyVO.PK_CARD);	
		AssetVO[] cards = AMProxy.lookup(IAssetService.class).queryAssetVOByPk(pk_cards);
//		logvo.setItf_type("调试");
//		logvo.setByztonccresult("AlterBodyVO.PK_CARD:"+AlterBodyVO.PK_CARD+"||pk_cards:"+pk_cards.toString()+"||cards:"+cards.toString());
//		NCLocator.getInstance().lookup(IbyzLogRcord.class).RcordLogBYZ__RequiresNew(logvo);
		
		if (cards == null || cards.length == 0) {
			ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
					"02012010-0064")/* @res "卡片已经减少，请重新刷新 \n " */);
		}

		// <pk_accbook, List<AssetVO>> 账簿和卡片VO
		Map<String, List<AssetVO>> accbookAssetVOs = new HashMap<String, List<AssetVO>>();
		for (AssetVO assetVO : cards) {
			String pk_accbook = assetVO.getPk_accbook();
			if (accbookAssetVOs.get(pk_accbook) == null) {
				List<AssetVO> list = new ArrayList<AssetVO>();
				list.add(assetVO);
				accbookAssetVOs.put(pk_accbook, list);
			} else {
				accbookAssetVOs.get(pk_accbook).add(assetVO);
			}
		}

		// 原值变动和购买价款变动
		if (AlterTransiTypeConst.ORIGINVALUE.equals(transi_type) || AlterTransiTypeConst.CURRMONEY.equals(transi_type)
				|| AlterTransiTypeConst.FA_ALTER.equals(transi_type)) {

			// 卡片关联的类别
			List<String> pk_categorys = new ArrayList<String>();

			for (Map.Entry<String, List<AssetVO>> entry : accbookAssetVOs.entrySet()) {
				List<AssetVO> cardVOs = entry.getValue();

				for (AssetVO vo : cardVOs) {
					if (!pk_categorys.contains(vo.getPk_category())) {
						pk_categorys.add(vo.getPk_category());
					}
				}
			}

			// <pk_accbook+pk_category, 本币原值来源>
			Map<String, String> accbookCategoryMap = getLocalValueSourceKeyMap(headVO.getPk_org(),
					Arrays.asList(accbookAssetVOs.keySet().toArray(new String[0])), pk_categorys);

			if (accbookCategoryMap == null || accbookCategoryMap.size() == 0) {
				return;
			}

			// 错误提示
			StringBuffer errorMsg = new StringBuffer();

			// 查询财务账簿对应的名称
			Map<String, String> accbookNameByPK = AccbookManager.queryAccbookNamesByOrg(headVO.getPk_org(),
					headVO.getBusiness_date().toString());

			if (accbookNameByPK == null || accbookNameByPK.size() == 0) {
				ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
						"02012010-0065", null,
						new String[] { headVO.getBusiness_date().toString() })/*
																				 * @ res " 该组织在业务日期{0}时，尚未启用账簿。 \n"
																				 */);
			}

			for (Map.Entry<String, List<AssetVO>> entry : accbookAssetVOs.entrySet()) {
				String pk_accbook = entry.getKey();
				List<AssetVO> cardVOs = entry.getValue();

				for (AssetVO vo : cardVOs) {
					// 本币原值来源
					String localValueSource = accbookCategoryMap.get(pk_accbook + vo.getPk_category());

					// 本币原值来源原币原值或者购买价款
					if (StringUtils.isNotEmpty(localValueSource)
							&& ((localValueSource.trim().equals(AssetVO.ORIGINVALUE)
									&& transi_type.equals(AlterTransiTypeConst.ORIGINVALUE))
									|| (localValueSource.trim().equals(AssetVO.CURRMONEY)
											&& transi_type.equals(AlterTransiTypeConst.CURRMONEY))
									|| transi_type.equals(AlterTransiTypeConst.FA_ALTER))) {

						// 再校验本币原值
						if (errorMsg.length() == 0) {
							// 变动后原币原值
							UFDouble originvalue_alter = UFDouble.ZERO_DBL;
							if (localValueSource.trim().equals(AssetVO.ORIGINVALUE)) {
								originvalue_alter = (UFDouble) cardBodyVO.get(vo.getPk_card())
										.getAttributeValue(AlterKeyConst.ORIGINVALUE_ALTER);
							} else {
								// 变动后购买价款
								originvalue_alter = (UFDouble) cardBodyVO.get(vo.getPk_card())
										.getAttributeValue(AlterKeyConst.CURRMONEY_ALTER);
							}

							// 需要经过币种折算
							String pk_currency_src = vo.getPk_currency();
							originvalue_alter = CurrencyRateManager.getAccbookAmountByOpp(pk_accbook, pk_currency_src,
									originvalue_alter, headVO.getBusiness_date());

							// 最新本币原值
							UFDouble localvalue_after = UFDoubleUtils.add(vo.getLocaloriginvalue(), originvalue_alter);

							// 净残值
							UFDouble salvage = UFDoubleUtils.multiply(localvalue_after, vo.getSalvagerate()).div(100);

							// 净额
							UFDouble netring = UFDoubleUtils.sub(UFDoubleUtils.sub(localvalue_after, vo.getAccudep()),
									vo.getPredevaluate());
							if (netring.compareTo(salvage) < 0) {
								errorMsg.append(vo.getCard_code());
							}
						}
					} else
						continue;
				}
			}

			if (errorMsg.length() != 0) {
				ExceptionUtils.asBusinessException(
						nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0", "02012010-0068", null,
								new String[] { errorMsg.toString() }))/*
																		 * @ res "卡片编号为{0}的卡片中净额小于净残值，请修改。 \n"
																		 */;
			}
		}
	}

	/**
	 * 批量得到本币原址的来源 <b>参数说明</b>
	 * 
	 * @param pk_org
	 * @param accbooks
	 * @param pk_categorys
	 * @return <pk_accbook+pk_category, 本币原值来源>
	 *         <p>
	 * @author weizq
	 * @throws BusinessException
	 * @time 2011-1-21 上午11:52:08
	 */
	private Map<String, String> getLocalValueSourceKeyMap(String pk_org, List<String> accbooks,
			List<String> pk_categorys) throws BusinessException {

		// <pk_accbook+pk_category, 本币原值来源>
		Map<String, String> accbooksMap = new HashMap<String, String>();

		for (String pk_accbook : accbooks) {
			// <pk_category, 本币原汁来源>
			Map<String, String> categoryFromLocalvage = AMProxy.lookup(IAccbookInfoService.class).queryFormula(pk_org,
					pk_categorys.toArray(new String[0]), pk_accbook);

			for (Map.Entry<String, String> categoryFrom : categoryFromLocalvage.entrySet()) {
				String pk_category = categoryFrom.getKey();
				String from = categoryFrom.getValue();
				accbooksMap.put(pk_accbook + pk_category, from);
			}
		}

		return accbooksMap;
	}

	/**
	 * 验证多账簿的情况：如果操作员自定义了资产变动单，将财务字段，业务字段都配到了一个模版上，不需要再做较验，财务字段变动会变化当前账簿的卡片字段，
	 * 业务字段变化所有的账簿下的在役卡片都会变化；
	 * 
	 * @param billVO
	 * @throws BusinessException
	 * @date 2010-5-7
	 */
	private void checkAccbook(AlterVO billVO, List<String> showAlterKeyList) throws BusinessException {

		AlterHeadVO headVO = (AlterHeadVO) billVO.getParentVO();
		String pk_accbook = headVO.getPk_accbook();
		String pk_org = headVO.getPk_org();
		UFDate biz_date = headVO.getBusiness_date();
		boolean isOneAccbook = true;
		Map<String, String> map = AccbookManager.queryAccbookNamesByOrg(pk_org, StringUtils.toString(biz_date));
		if (!MapUtils.isEmpty(map) && map.size() > 1) {
			isOneAccbook = false;
		}

		if (isOneAccbook)
			return;

		// 下面判断多账簿的情况

		// 只有模板中有财务字段，并且选择了 业务账簿，才不能操作，其他的情况都能操作
		if (AccbookManager.isBizAccbook(pk_accbook)) {
			Set<String> accountSet = new HashSet<String>();
			CollectionUtils.addAll(accountSet, AssetFieldConst.ACCOUNT_FIELD);
			for (String key : showAlterKeyList) {
				// 除了折旧承担部门
				if (!key.equals(AssetFieldConst.PAYDEPT_FLAG) && accountSet.contains(key)) {
					ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
							"02012010-0069")/*
											 * @res "多账簿 表体包含财务信息，选择财务账簿进行财务信息调整！"
											 */);
				}
			}
		}
	}

	/**
	 * 后台推式新增保存的方法，不考虑流量
	 * 
	 * @param context
	 * @param billVO
	 * @return
	 * @throws BusinessException
	 * @date 2010-5-26
	 */
	protected AlterVO insertPushAlterVO(LoginContext context, AlterVO billVO, List<String> showAlterKeyList)
			throws BusinessException {

		// 变动项目不能为空
		if (CollectionUtils.isEmpty(showAlterKeyList)) {
			throw new IllegalArgumentException(" showAlterKeyList can't be Empty!");
		}

		// 校验账簿
		checkAccbook(billVO, showAlterKeyList);

		// 判断是否能够进行
		AuditInfoUtil.addData(billVO.getParent());

		// 处理多币种, 币种汇率
		dealMultiCurrency(billVO);

		AlterVO retAlterVO = ArrayUtils.getFirstElem(super.pushSaveBillVO(billVO));

		// 保存明细数据
		AlterSheetVO[] sheetVOs = AlterHelper.generaterSheetVOs(retAlterVO, showAlterKeyList);
		VOPersistUtil.insert(sheetVOs);

		// 不能使用finally块进行:因为保存报错了，前台依然处于编辑状态，应该由取消按钮来解锁 或者 保存成功了解锁。
		releasePKCardLock(billVO);

		return retAlterVO;
	}

	/**
	 * 盘点调审核
	 * 
	 * @param context
	 * @param billVO
	 * @return
	 * @throws BusinessException
	 * @date 2010-5-26
	 */
	protected AlterVO approveAlterVO(LoginContext context, AlterVO billVO, List<String> showAlterKeyList)
			throws BusinessException {

		// 校验资产类别变动时是否关联账簿，防止在此之前将账簿信息中资产类别删除造成问题 by guozhq
		checkCategory(billVO, showAlterKeyList);
		// 配置业务规则
		// 审核通过后规则
		List<IRule<AlterVO>> approvePassAfterRules = new ArrayList<IRule<AlterVO>>();

		// 1. 更新卡片历史表
		approvePassAfterRules.add(new AlterWriteBackToCardAfterRule<AlterVO>(true));
		// 2. 增加单据LogVO
		approvePassAfterRules.add(new CreateBillLogAfterRule<AlterVO>(LogTypeConst.alter));
		// 3. 更新表体卡片日志的
		approvePassAfterRules.add(new UpdateCardLogAfterRule<AlterVO>(true));
		// 4. 重新折旧计提标志
		approvePassAfterRules.add(new AlterUpdateDepLogAfterRule());
		// 5. 判断如果是资本化调整单，则需要联动生成其他账簿变动单据
		approvePassAfterRules.add(new AlterDealValueAfterRule<AlterVO>(true));
		// 6. 发送会计平台
		approvePassAfterRules.add(new AlterSendFipAfterRule());

		// 审批通过后规则
		ActionContext<AlterVO> actionContext = new ActionContext<AlterVO>("InsertAction");
		PfParameterVO parameterVo = new PfParameterVO();
		parameterVo.m_userObj = showAlterKeyList;
		actionContext.addImutableUserObj(RuleConst.PfParameterVo, parameterVo);
		for (IRule<AlterVO> rule : approvePassAfterRules) {
			rule.process(actionContext, billVO);
		}

		return billVO;
	}

	/*
	 * 推式生单的规则
	 * 
	 * @date 2010-5-28
	 */
	@Override
	protected void initPushSaveActionRules(IActionTemplate<AlterVO> insertAction) {

		super.initPushSaveActionRules(insertAction);
		// 保存校验类
		List<Validator> validators = new ArrayList<Validator>();
		// 校验卡片合法性
		validators.add(new CheckCardLegalValidator());
		// 校验最小未结账月
		validators.add(new CheckMinUnClosedBookPeriodValidator());
		// 校验是否制单
		validators.add(new CheckHasFipMakeVoucherForAccbooks());

		insertAction.addBeforeRule(new ValidateServiceRule<AlterVO>(validators));

		// 增加更新卡片日志规则，更新【bill_code，bill_type，bill_status】
		insertAction.addBeforeRule(new UpdateCardLogAfterRule<AlterVO>(false));
		insertAction.addBeforeRule(new PKAccbookBeforeRule<AlterVO>());
		// 更新消息来源状态
		insertAction.addAfterRule(new UpdateSrcMsgState4BillAfterRule<AlterVO>());
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void initDeleteActionRules(IActionTemplate<AlterVO> deleteAction) {

		super.initDeleteActionRules(deleteAction);
		// saga状态校验
		deleteAction.addBeforeRule(new VOSagasStatusCheckBeforeRule<AlterVO>());
		// 增加更新卡片日志规则，清空【bill_code，bill_type，bill_status】
		deleteAction.addBeforeRule(new UpdateCardLogAfterRule<AlterVO>(false, true));
		deleteAction.addAfterRule(new AlterBillCodeDeleteRule());
	}

	@Override
	protected void initInsertActionRules(IActionTemplate<AlterVO> insertAction) {

		super.initInsertActionRules(insertAction);
		// 保存校验类
		List<Validator> validators = new ArrayList<Validator>();
		// 添加是否启用账簿的校验
		validators.add(new FAAccbookCheckSealRule());
		// 校验消息在保存时是否被删除
		validators.add(new SrcMessageExistValidator());
		// 校验卡片合法性
		validators.add(new CheckCardLegalValidator());
		// 校验最小未结账月
		validators.add(new CheckMinUnClosedBookPeriodValidator());
		// 校验是否制单
		validators.add(new CheckHasFipMakeVoucherForAccbooks());
		// 如果是资产传过来的，则需要校验来源单据是否是审核
		// validators.add(new SrcBillUnApproveValidator<AlterVO>()); //
		// SrcMessageExistValidator该校验已经包含了
		// 如果是从项目方打开消息生成变动单，校验来源单据状态是否合法。
		validators.add(new AlterSrcBillLegalValidator());

		insertAction.addBeforeRule(new ValidateServiceRule<AlterVO>(validators));

		// 增加更新卡片日志规则，更新【bill_code，bill_type，bill_status】
		insertAction.addBeforeRule(new BillCodeInsertBeforeRule<AlterVO>());
		insertAction.addBeforeRule(new PKAccbookBeforeRule<AlterVO>());
		insertAction.addAfterRule(new BillCodeInsertAfterRule<AlterVO>());
		// 更新消息来源状态
		insertAction.addAfterRule(new UpdateCardLogAfterRule<AlterVO>(false));
		insertAction.addAfterRule(new UpdateSrcMsgState4BillAfterRule<AlterVO>());
	}

	@SuppressWarnings("rawtypes")
	@Override
	protected void initUpdateActionRules(IActionTemplate<AlterVO> updateAction) {

		super.initUpdateActionRules(updateAction);
		// 更新校验类
		List<Validator> validators = new ArrayList<Validator>();
		// 校验卡片合法性
		validators.add(new CheckCardLegalValidator());
		// 校验最小未结账月
		validators.add(new CheckMinUnClosedBookPeriodValidator());
		// 如果是资产传过来的，则需要校验来源单据是否是审核
		validators.add(new SrcBillUnApproveValidator());
		// 校验是否制单
		validators.add(new CheckHasFipMakeVoucherForAccbooks());
		updateAction.addBeforeRule(new ValidateServiceRule<AlterVO>(validators));

		// 增加更新卡片日志规则，更新【bill_code，bill_type，bill_status】
		updateAction.addBeforeRule(new UpdateCardLogAfterRule<AlterVO>(false));
		updateAction.addBeforeRule(new BillCodeUpdateRule<AlterVO>());
		updateAction.addBeforeRule(new PKAccbookBeforeRule<AlterVO>());
		updateAction.addAfterRule(new UpdateCardLogAfterRule<AlterVO>(false, false, true));
	}

	@Override
	protected void initCommitActionRules(IActionTemplate<AlterVO> template) {
		// saga状态校验
		template.addBeforeRule(new VOSagasStatusCheckBeforeRule<AlterVO>());
		// 影像扫描
		template.addBeforeRule(new ReceiptScanBeforeRule<AlterVO>());
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void initApproveRule(ApproveActionTemplate<AlterVO> template) {

		// 初始化审批校验类列表。
		List<Validator> validators = new ArrayList<Validator>();
		// 添加是否启用账簿的校验
		validators.add(new FAAccbookCheckSealRule());
		// 校验[变动后资产编码]回写时，是否有重复
		validators.add(new AssetCodeIsSameCheckRule(true));
		// 添加判断财务是否已经制成折旧清单的校验。
		validators.add(new CheckHasFipMakeVoucherForAccbooks());
		// 校验变动后资产类别是否关联账簿 by guozhq
		validators.add(new AlterCategoryCheckRule());
		template.addApprovedBeforeRule(new ValidateServiceRule<AlterVO>(validators));
		// saga状态校验
		template.addApprovedBeforeRule(new VOSagasStatusCheckBeforeRule<AlterVO>());

		// 配置业务规则
		// 审核通过后规则
		List<IRule<AlterVO>> approvePassAfterRules = new ArrayList<IRule<AlterVO>>();

		// 同步单据状态到报账人门户
		approvePassAfterRules.add(new UpdateBillStatusOfWorkFlowAfterRule<AlterVO>());
		// 1. 更新卡片历史表
		approvePassAfterRules.add(new AlterWriteBackToCardAfterRule<AlterVO>(true));
		// 2. 增加单据LogVO
		approvePassAfterRules.add(new CreateBillLogAfterRule<AlterVO>(LogTypeConst.alter));
		// 3. 更新表体卡片日志的
		approvePassAfterRules.add(new UpdateCardLogAfterRule<AlterVO>(true));
		// 4. 重新折旧计提标志
		approvePassAfterRules.add(new AlterUpdateDepLogAfterRule());
		// 5. 判断如果是价值调整单，则需要联动生成其他账簿变动单据
		approvePassAfterRules.add(new AlterDealValueAfterRule<AlterVO>(true));
		// 6. 判断如果是外模块推资产追溯调整单，则需要联动生成其他账簿变动单据
		approvePassAfterRules.add(new AlterPushTraceAfterRule<AlterVO>(true));
		// 7. 发送会计平台
		approvePassAfterRules.add(new AlterSendFipAfterRule());
		// 8. 推送给ARC
//		approvePassAfterRules.add(new SendARCAlterRule());

		// 审批通过后规则
		template.addApprovePassAfterRule(approvePassAfterRules);

	}

	@Override
	protected void initUnApproveRule(UnApproveActionTemplate<AlterVO> template) {

		// 保存校验类
		List<Validator> validators = new ArrayList<Validator>();
		// 添加是否启用账簿的校验
		validators.add(new FAAccbookCheckSealRule());
		// 校验工单资本化报告账簿不能弃审
		validators.add(new AlterCapitalUnapproveValidator());
		// 校验[变动前资产编码]回写时，是否有重复
		validators.add(new AssetCodeIsSameCheckRule(false));
		// 校验卡片合法性
		validators.add(new AlterCheckCardLegalValidator());
		// 最小未结账月
		validators.add(new CheckMinUnClosedBookPeriodValidator());
		// 添加判断财务是否已经制成折旧清单的校验。
		validators.add(new CheckHasFipMakeVoucherForAccbooks());

		// 弃审前业务规则
		List<IRule<AlterVO>> unApprovedBeforeRules = new ArrayList<IRule<AlterVO>>();
		// saga状态校验
		unApprovedBeforeRules.add(new VOSagasStatusCheckBeforeRule<AlterVO>());
		unApprovedBeforeRules.add(new ValidateServiceRule<AlterVO>(validators));
		template.addUnApprovedBeforeRules(unApprovedBeforeRules);

		// 最后取消审核人取消审核业务规则
		List<IRule<AlterVO>> lastUnApprovedAfterRules = new ArrayList<IRule<AlterVO>>();

		// 1. 记录报告账簿的单据, 为了给会计平台用
		lastUnApprovedAfterRules.add(new AlterStorageBillVORule<AlterVO>());
		// 1. 发送会计平台(删除)
		lastUnApprovedAfterRules.add(new AlterDeleteFipAfterRule());
		// 2. 更新卡片历史表
		lastUnApprovedAfterRules.add(new AlterWriteBackToCardAfterRule<AlterVO>(false));
		// 3. 删除单据LogVO
		lastUnApprovedAfterRules.add(new DeleteBillLogAfterRule<AlterVO>());
		// 4. 更新表体卡片日志的
		lastUnApprovedAfterRules.add(new UpdateCardLogAfterRule<AlterVO>(false));
		// 5. 重新折旧计提标志
		lastUnApprovedAfterRules.add(new AlterUpdateDepLogAfterRule());
		// 6. 判断如果是资本化调整单，则需要联动生成其他账簿变动单据
		lastUnApprovedAfterRules.add(new AlterDealValueAfterRule<AlterVO>(false));
		// 7. 判断如果是外模块推资产追溯调整单，则需要联动生成其他账簿变动单据
		lastUnApprovedAfterRules.add(new AlterPushTraceAfterRule<AlterVO>(false));

		// 添加取消审核后业务规则
		template.addLastUnApprovedAfterRules(lastUnApprovedAfterRules);
	}

	/**
	 * 初始化收回业务规则。
	 * 
	 * @author zhangypm
	 * @time 2020年1月10日
	 */
	@Override
	protected void initUnSaveActionRules(IActionTemplate<AlterVO> template) {
		super.initUnSaveActionRules(template);
		// saga状态校验
		template.addBeforeRule(new VOSagasStatusCheckBeforeRule<AlterVO>());
	}

	/**
	 * 前台调用的提交方法，处理流量
	 * 
	 * @see nc.itf.fa.prv.IReduce#commit(nc.vo.uif2.LoginContext,
	 *      nc.vo.fa.reduce.AlterVO)
	 * 
	 * @date 2010-5-26
	 */
	@Override
	public AlterVO commit(LoginContext context, AlterVO billVO) throws BusinessException {

		// 审核
		billVO = commitAlerVO(context, billVO);

		return billVO;

	}

	/**
	 * 收回
	 * 
	 * @param vos
	 * @return
	 * @throws BusinessException
	 */
	@Override
	public Object unSave(AlterVO[] vos) throws BusinessException {
		return super.unSaveBillVOs(vos);
	}

	/**
	 * 后台调用的提交方法，不处理流量
	 * 
	 * @param context
	 * @param billVO
	 * @return
	 * @throws BusinessException
	 * @date 2010-5-26
	 */
	protected AlterVO commitAlerVO(LoginContext context, AlterVO billVO) throws BusinessException {

		return ArrayUtils.getFirstElem(commitBillVO(billVO));
	}

	/**
	 * 前台调用的删除方法，处理流量
	 * 
	 * @see nc.itf.fa.prv.IAlter#delete(nc.vo.uif2.LoginContext,
	 *      nc.vo.fa.alter.AlterVO)
	 * 
	 * @date 2010-5-26
	 */
	@Override
	public void delete(LoginContext context, AlterVO billVO) throws BusinessException {

		// 重新加载
		billVO = reloadAlterVO(billVO.getPrimaryKey());
		// 删除数据
		deleteAlterVO(context, billVO);

	}

	/**
	 * 重新加载变动单
	 * 
	 * @param primaryKey
	 * @return
	 * @throws BusinessException
	 * @date 2010-5-26
	 */
	@Override
	public AlterVO reloadAlterVO(String primaryKey) throws BusinessException {

		// 先查表头
		AlterVO billVO = ArrayUtils.getFirstElem(queryAlterVOByPKs(new String[] { primaryKey }, false));

		if (billVO == null) {
			return null;
		}

		// 账簿
		String pk_accbook = (String) billVO.getParentVO().getAttributeValue(CommonKeyConst.pk_accbook);

		// 再查询指定账簿的表体数据
		billVO.setChildrenVO(queryAlterBodyVOs(primaryKey, pk_accbook));

		return billVO;
	}

	/**
	 * 批量重新加载变动单 方法功能描述：简要描述本方法的功能。
	 * <p>
	 * <b>参数说明</b>
	 * 
	 * @param primaryKeys 变动单主键
	 * @return
	 * @throws BusinessException
	 *                           <p>
	 * @author weizq
	 * @time 2010-12-23 下午04:51:03
	 */
	@Override
	public AlterVO[] reloadAlterVOs(String[] primaryKeys) throws BusinessException {

		List<AlterVO> alterVOs = new ArrayList<AlterVO>();
		for (String pk : primaryKeys) {
			AlterVO billVO = reloadAlterVO(pk);
			if (billVO == null) {
				continue;
			}
			// modified by wangweiak 2015-07-17
			// 为alterVO补上showAlterKeyList属性值，解决从【消息中心】-【工作任务】
			// 处【批量审批】时，不走ApproveAction类，导致getUserObject()无法正常注入，在后续AlterWriteBackToCardAfterRule
			// 通过Object m_userObj = ((PfParameterVO)
			// context.getImutableUserObj(RuleConst.PfParameterVo)).m_userObj;
			// 取不到值，导致【批量审批】失败问题
			if (billVO.getChildrenVO() instanceof AlterBodyVO[]) {
				AlterBodyVO[] bodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();
				String[] pk_alter_bs = VOManager.getAttributeValueArray(bodyVOs, AlterBodyVO.PK_ALTER_B);

				// 分开查表体数据
				AlterSheetVO[] alterSheetVOs = QueryUtil.queryVOByCond(AlterSheetVO.class,
						" pk_alter_b in " + InSqlManager.getInSQLValue(pk_alter_bs), null);
				List<String> item_codesList = VOManager.getAttributeValueList(alterSheetVOs, AlterSheetVO.ITEM_CODE,
						true, false);
				billVO.setShowAlterKeyList(item_codesList);
			}
			alterVOs.add(billVO);
		}

		return alterVOs.toArray(new AlterVO[0]);
	}

	/**
	 * 查询变动单，包括(AlterSheetVO[])
	 * <p>
	 * 
	 * @param primaryKeys
	 * @return
	 * @throws BusinessException
	 *                           <p>
	 * @author weizq
	 * @time 2011-4-2 上午08:59:41
	 */
	public AlterVO[] queryAlters(String[] primaryKeys) throws BusinessException {

		// 查询变动单和表体
		AlterVO[] alterVOs = queryAlterVOByPKs(primaryKeys, true);

		List<String> bodyPKs = new ArrayList<String>();
		Map<String, AlterBodyVO> bodyVOsMap = new HashMap<String, AlterBodyVO>();
		for (AlterVO alterVO : alterVOs) {
			AlterBodyVO[] bodyVOs = (AlterBodyVO[]) alterVO.getChildrenVO();
			for (AlterBodyVO bodyVO : bodyVOs) {
				if (!bodyPKs.contains(bodyVO.getPk_alter_b())) {
					bodyPKs.add(bodyVO.getPk_alter_b());
				}
				bodyVOsMap.put(bodyVO.getPrimaryKey(), bodyVO);
			}
		}

		// <pk_alter_b, List<AlterSheetVO>>
		Map<String, List<AlterSheetVO>> bodySheetsMap = new HashMap<String, List<AlterSheetVO>>();
		if (bodyPKs != null && bodyPKs.size() != 0) {
			bodySheetsMap = queryAlterSheetVOByBodyPKs(bodyPKs.toArray(new String[0]));
		}

		for (Map.Entry<String, List<AlterSheetVO>> entry : bodySheetsMap.entrySet()) {
			String pk_alter_b = entry.getKey();

			AlterBodyVO bodyVO = bodyVOsMap.get(pk_alter_b);

			bodyVO.setAltersheetvos(entry.getValue().toArray(new AlterSheetVO[0]));
		}

		for (AlterVO alterVO : alterVOs) {
			for (AlterBodyVO bodyVO : (AlterBodyVO[]) alterVO.getChildrenVO()) {
				bodyVO.setAltersheetvos(bodySheetsMap.get(bodyVO.getPrimaryKey()).toArray(new AlterSheetVO[0]));
			}
		}

		return alterVOs;
	}

	/**
	 * 后台调用的删除方法，不处理流量
	 * 
	 * @param context
	 * @param billVO
	 * @throws BusinessException
	 * @date 2010-5-26
	 */
	public void deleteAlterVO(LoginContext context, AlterVO billVO) throws BusinessException {

		// 单据加锁
		LockManager.lock(new BaseLockData<AlterVO>(billVO));

		AlterBodyVO[] bodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();

		deleteSheetVOs(bodyVOs);
		super.deleteBillVO(billVO);
	}

	private ILogService getLogService() {

		return AMProxy.lookup(ILogService.class);
	}

	/**
	 * 前台调用的更新方法，处理流量
	 * 
	 * @see nc.itf.fa.prv.IAlter#update(nc.vo.uif2.LoginContext,
	 *      nc.vo.fa.alter.AlterVO)
	 * 
	 * @date 2010-5-26
	 */
	@Override
	public TransportBillVO update(LoginContext context, AlterVO billVO, List<String> showAlterKeyList)
			throws BusinessException {

		// 调用保存方法
		billVO = updateAlterVO(context, billVO, showAlterKeyList);

		// 流量处理
		TransportBillVO transportBillVO = BillTransportTool.createTransportBill(billVO, BillTransportTool.MODE_UPDATE);
		return transportBillVO;
	}

	/**
	 * 后台调用的更新方法，不处理流量
	 * 
	 * @param context
	 * @param billVO
	 * @return
	 * @throws BusinessException
	 * @date 2010-5-26
	 */
	protected AlterVO updateAlterVO(LoginContext context, AlterVO billVO, List<String> showAlterKeyList)
			throws BusinessException {

		// 加单据锁
		LockManager.lock(new BaseLockData<AlterVO>(billVO));

		// 校验
		validateAlterData(billVO, showAlterKeyList);

		// 先删除原先所有的孙表信息，再重新插入新的孙表数据
		AlterBodyVO[] bodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();
		deleteSheetVOs(bodyVOs);

		// 处理多币种
		dealMultiCurrency(billVO);

		// 更新单据时，需要先删除旧表体卡片的日志，再新增新表体卡片的日志
		AlterHeadVO headVO = (AlterHeadVO) billVO.getParentVO();
		String[] pk_cards = queryBodyCardId(headVO.getPrimaryKey(), headVO.getPk_accbook());
		String bill_code = headVO.getBill_code();
		String bill_type = headVO.getBill_type();
		Integer bill_status = headVO.getBill_status();
		String pk_accbook = headVO.getPk_accbook();

		// 持久化
		AlterVO retVo = ArrayUtils.getFirstElem(super.updateBillVO(new AlterVO[] { billVO }, null));

		// 设置修改后变动单信息, 不用retVo这个的原因是直接点修改，保存操作，将界面计算属性的值设置为空
		setAlterVOInfo(billVO, retVo);

		// 注入使用部门属性
		AlterBodyVO[] retBodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();
		if (ArrayUtils.isNotEmpty(retBodyVOs)) {
			for (int i = 0; i < retBodyVOs.length; i++) {
				AlterBodyVO tbodyVO = retBodyVOs[i];
				// 变动前使用部门
				tbodyVO.setOld_deptscalevos(bodyVOs[i].getOld_deptscalevos());
				// 变动后使用部门
				tbodyVO.setNew_deptscalevos(bodyVOs[i].getNew_deptscalevos());
			}
		}

		// 再新增新表体卡片的日志
		pk_cards = queryBodyCardId(headVO.getPrimaryKey(), headVO.getPk_accbook());

		// 再重新更新卡片日志中的bill_code
		updateCardLog(pk_accbook, bill_code, bill_type, bill_status, pk_cards);

		// 保存明细数据 先去除删除的行
		BaseVOUtils.removeDeletedBodys(billVO);
		AlterSheetVO[] sheetVOs = AlterHelper.generaterSheetVOs(billVO, showAlterKeyList);
		if (ArrayUtils.isNotEmpty(sheetVOs)) {
			VOPersistUtil.insert(sheetVOs);
		}

		// 不能使用finally块进行:因为保存报错了，前台依然处于编辑状态，应该由取消按钮来解锁 或者 保存成功了解锁。
		releasePKCardLock(billVO);

		return billVO;
	}

	/**
	 * 设置修改后变动单信息
	 * 
	 * @param retVo
	 * @param billVO
	 * @time 2011-3-22 下午07:13:10
	 */
	private void setAlterVOInfo(AlterVO billVO, AlterVO retVo) {

		if (retVo == null || billVO == null) {
			return;
		}
		// 由于是重新生成的表体，则需要重新设置ts
		billVO.getParent().setAttributeValue(CommonKeyConst.ts, retVo.getParent().getAttributeValue(CommonKeyConst.ts));
		// 更新 bill_status
		billVO.getParent().setAttributeValue(CommonKeyConst.bill_status,
				retVo.getParent().getAttributeValue(CommonKeyConst.bill_status));
		if (billVO.getChildrenVO() == null) {
			return;
		}
		// <pk_card, pk_alter_b>
		AlterBodyVO[] retBodyVOs = (AlterBodyVO[]) retVo.getChildrenVO();
		Map<String, String> cardRetBodyMap = new HashMap<String, String>();
		for (AlterBodyVO ret : retBodyVOs) {
			cardRetBodyMap.put(ret.getPk_card(), ret.getPk_alter_b());
		}

		for (AlterBodyVO vo : (AlterBodyVO[]) billVO.getChildrenVO()) {
			if (vo.getStatus() == VOStatus.DELETED) {
				continue;
			}
			String pk_alter_b = cardRetBodyMap.get(vo.getPk_card());
			vo.setPk_alter_b(pk_alter_b);
		}

	}

	/**
	 * 删除孙表
	 * 
	 * @param bodyVOs
	 * @throws BusinessException
	 */
	private void deleteSheetVOs(AlterBodyVO[] bodyVOs) throws BusinessException {

		if (ArrayUtils.isEmpty(bodyVOs))
			return;

		List<String> deleteBodyPKs = VOManager.getAttributeValueList(bodyVOs, AlterBodyVO.PK_ALTER_B);

		if (CollectionUtils.isEmpty(deleteBodyPKs)) {
			return;
		}
		String sql = " dr = 0 and pk_alter_b in " + InSqlManager.getInSQLValue(deleteBodyPKs);
		new DBAccessUtil().deleteByCond(new AlterSheetVO().getTableName(), sql);
	}

	@Override
	public AlterBodyVO[] queryAlterBodyVOs(String parentPK, String pk_accbook) throws BusinessException {

		String whereSql = " dr =0 and pk_alter = '" + parentPK + "' ";
		if (AccbookManager.isBizAccbook(pk_accbook)) {
			pk_accbook = FlagConsts.FLAG_NULL;
		}
		whereSql = whereSql + " and pk_accbook = '" + pk_accbook + "' ";
		whereSql = " pk_alter_b in ( select min(pk_alter_b) from fa_alter_b where " + whereSql + " group by pk_card ) ";

		AlterBodyVO[] bodyVOs = QueryUtil.queryVOByCond(AlterBodyVO.class, whereSql, null);
		// 加载明细内容
		AlterHelper.loadAlterSheet(bodyVOs);
		return bodyVOs;
	}

	@Override
	public AlterBodyVO[] queryAlterBodyVOsNoFilter(String parentPK, String pk_accbook) throws BusinessException {

		String whereSql = " dr =0 and pk_alter = '" + parentPK + "' ";
		if (AccbookManager.isBizAccbook(pk_accbook)) {
			pk_accbook = FlagConsts.FLAG_NULL;
		}
		whereSql = whereSql + " and pk_accbook = '" + pk_accbook + "' ";

		AlterBodyVO[] bodyVOs = QueryUtil.queryVOByCond(AlterBodyVO.class, whereSql, null);
		// 加载明细内容
		AlterHelper.loadAlterSheet(bodyVOs);
		return bodyVOs;
	}

	/**
	 * 根据PKs查询变动单统一的接口的，
	 * 
	 * @param whereSql     whereSql
	 * @param orderColumns 排序的字段
	 * @param isQueryBody  是否查询表体
	 * @return
	 * @throws BusinessException
	 * @date 2010-4-13
	 */
	private AlterVO[] queryAlterVOByPKs(String[] pks, boolean isQueryBody) throws BusinessException {

		String sql = " pk_alter in " + InSqlManager.getInSQLValue(pks);
		return queryAlterVOByHeadCond(sql, isQueryBody);

	}

	/**
	 * 根据where条件查询变动单统一的接口的，
	 * 
	 * @param whereSql     whereSql
	 * @param orderColumns 排序的字段
	 * @param isQueryBody  是否查询表体
	 * @return
	 * @throws BusinessException
	 * @date 2010-4-13
	 */
	private AlterVO[] queryAlterVOByHeadCond(String whereSql, boolean isQueryBody) throws BusinessException {

		// 根据表头条件来查询
		return QueryUtil.queryBillVOByHeadCond(AlterVO.class, whereSql, null, isQueryBody);
	}

	@SuppressWarnings({ "unchecked", "deprecation" })
	@Override
	public String[] queryPksByWhereSql(String whereSql, LoginContext context) throws BusinessException {

		SuperVO superVO = BaseVOUtils.initClass(AlterHeadVO.class);
		String pk_fieldName = superVO.getPKFieldName();
		StringBuffer sql = new StringBuffer("select ").append(pk_fieldName).append(" from ");
		sql.append(superVO.getTableName() + " as h  where dr = 0 and pk_group = '"
				+ InvocationInfoProxy.getInstance().getGroupId() + "'");
		if (whereSql != null && whereSql.trim().length() > 0)
			sql.append("and ").append(whereSql);

		DBAccessUtil dbAcc = new DBAccessUtil();
		List<String> list = (List<String>) dbAcc.getBaseDAO().executeQuery(sql.toString(), new ColumnListProcessor());
		if (list != null && list.size() > 0)
			return list.toArray(new String[list.size()]);

		return null;
	}

	/**
	 * 后台解卡片锁: 注意：解锁不一定都需要放在finally代码块中，得根据具体的业务流程进行考虑，带用本方法时必须要注释说明是否需要finally块。
	 * 
	 * @param billVO
	 * @throws BusinessException
	 * @date 2010-3-19
	 */
	private void releasePKCardLock(AlterVO billVO) throws BusinessException {

		if (billVO == null || ArrayUtils.isEmpty(billVO.getChildrenVO()))
			return;

		AlterBodyVO[] bodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();
		List<String> pk_cards = new ArrayList<String>();
		for (int i = 0; i < bodyVOs.length; i++) {
			String pk_card = bodyVOs[i].getPk_card();
			if (StringUtils.isEmpty(pk_card))
				continue;

			pk_cards.add(pk_card);
		}
		LockManager.releasePKLocks(pk_cards.toArray(new String[0]), InvocationInfoProxy.getInstance().getUserId());

		AlterHeadVO headVO = (AlterHeadVO) billVO.getParentVO();
		String srcBillPk = headVO.getPk_bill_src();
		if (StringUtils.isNotEmpty(srcBillPk)) {
			LockManager.releasePKLocks(new String[] { srcBillPk }, InvocationInfoProxy.getInstance().getUserId());
		}

	}

	/**
	 * 处理多币种
	 * 
	 * @param billVO
	 * @param isCurrencyRate 是否币种折算
	 * @throws BusinessException
	 * @date 2010-3-30
	 */
	private void dealMultiCurrency(AlterVO billVO) throws BusinessException {

		AlterHeadVO headVO = (AlterHeadVO) billVO.getParentVO();
		AlterBodyVO[] bodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();

		if (ArrayUtils.isEmpty(bodyVOs)) {
			return;
		}

		// 默认组织的主账簿
		String pk_accbook = headVO.getPk_accbook();
		if (AccbookManager.isBizAccbook(pk_accbook)) {
			pk_accbook = AccbookManager.queryMainAccbookIDByFinanceOrg(headVO.getPk_org());
		}
		for (AlterBodyVO bodyVO : bodyVOs) {
			bodyVO.setPk_group(headVO.getPk_group());
			CurrencyRateManager.setLocalMoneyByAccbook(bodyVO, AlterKeyConst.MULTI_CURRENCY_FIELDS, pk_accbook,
					headVO.getBusiness_date());

			// 处理币种汇率
			// 来源币种
			// String pk_currency_src = (String)
			// bodyVO.getAttributeValue(AlterKeyConst.PK_SRC_CURRENCY);
			// if (StringUtils.isNotEmpty(pk_currency_src)) {
			// //变动部分本币原值
			// UFDouble alterLocalValue = (UFDouble)
			// bodyVO.getAttributeValue(AlterKeyConst.LOCALORIGINVALUE_ALTER);
			// //变动前本币原值
			// UFDouble beforeLocalValue = (UFDouble)
			// bodyVO.getAttributeValue(AlterKeyConst.LOCALORIGINVALUE_BEFORE);
			//
			// //需要经过币种折算
			// UFDouble alterLocalValueByCurrencyRate = CurrencyRateManager
			// .getAccbookAmountByOpp(pk_accbook, pk_currency_src,
			// alterLocalValue, headVO.getBusiness_date());
			//
			// bodyVO.setAttributeValue(AlterKeyConst.LOCALORIGINVALUE_ALTER,
			// alterLocalValueByCurrencyRate);
			// bodyVO.setAttributeValue(AlterKeyConst.LOCALORIGINVALUE_AFTER,
			// UFDoubleUtils.add(beforeLocalValue,
			// alterLocalValueByCurrencyRate));
			// }
		}

	}

	@Override
	public boolean isMadeAlterTrace(String pk_accbook, UFDate bizDate, String... pk_cards) throws BusinessException {

		AccperiodVO periodVO = PeriodManager.getInstance().queryPerriodMonth(pk_accbook, bizDate);

		StringBuilder sqlBuilder = new StringBuilder();
		sqlBuilder.append(" select top 1 '1' from fa_alter h");
		sqlBuilder.append(" left outer join fa_alter_b b on h.pk_alter = b.pk_alter ");
		sqlBuilder.append(" where h.dr = 0 and b.dr = 0 ");
		sqlBuilder.append(" b.pk_card in " + InSqlManager.getInSQLValue(pk_cards));
		sqlBuilder.append(" and h.business_date >= '" + periodVO.getStartdate().toStdString() + "'");
		sqlBuilder.append(" and h.business_date <= '" + periodVO.getEnddate().toStdString() + "'");
		sqlBuilder.append(" and h.pk_accbook = '" + pk_accbook + "'");
		sqlBuilder.append(" and h.transi_type= 'HG-04'");

		return (Boolean) new BaseDAO().executeQuery(sqlBuilder.toString(), new BooleanProcessor());

	}

	@SuppressWarnings("unchecked")
	@Override
	public Set<String> queryMadeAlterTrace(String pk_accbook, UFDate bizDate) throws BusinessException {

		AccperiodVO periodVO = PeriodManager.getInstance().queryPerriodMonth(pk_accbook, bizDate);

		StringBuilder sqlBuilder = new StringBuilder();
		sqlBuilder.append(" select b.pk_card from fa_alter h");
		sqlBuilder.append(" left outer join fa_alter_b b on h.pk_alter = b.pk_alter ");
		sqlBuilder.append(" where h.dr = 0 and b.dr = 0 ");
		sqlBuilder.append(" and h.business_date >= '" + periodVO.getStartdate().toPersisted() + "'");
		sqlBuilder.append(" and h.business_date <= '" + periodVO.getEnddate().toPersisted() + "'");
		sqlBuilder.append(" and h.pk_accbook = '" + pk_accbook + "'");
		sqlBuilder.append(" and h.transi_type = 'HG-04'");

		return (Set<String>) new BaseDAO().executeQuery(sqlBuilder.toString(), new ColumnSetProcessor<String>());

	}

	@SuppressWarnings("unchecked")
	@Override
	public Set<String> queryMadeAlterTrace(String pk_alter, String pk_accbook, UFDate bizDate)
			throws BusinessException {

		AccperiodVO periodVO = PeriodManager.getInstance().queryPerriodMonth(pk_accbook, bizDate);

		StringBuilder sqlBuilder = new StringBuilder();
		sqlBuilder.append(" select b.pk_card from fa_alter h");
		sqlBuilder.append(" left outer join fa_alter_b b on h.pk_alter = b.pk_alter ");
		sqlBuilder.append(" where h.dr = 0 and b.dr = 0 ");
		sqlBuilder.append(" and h.business_date >= '" + periodVO.getStartdate().toPersisted() + "'");
		sqlBuilder.append(" and h.business_date <= '" + periodVO.getEnddate().toPersisted() + "'");
		sqlBuilder.append(" and h.pk_accbook = '" + pk_accbook + "'");
		sqlBuilder.append(" and h.transi_type = 'HG-04'");
		sqlBuilder.append(" and h.pk_alter <> '" + pk_alter + "'");

		return (Set<String>) new BaseDAO().executeQuery(sqlBuilder.toString(), new ColumnSetProcessor<String>());

	}

	@SuppressWarnings("unchecked")
	@Override
	public Set<String> queryMadeAlterTraceByPeriod(String pk_accbook, String year, String period, String... pk_cards)
			throws BusinessException {

		StringBuilder sqlBuilder = new StringBuilder();
		String[] periodVOs = PeriodManager.getInstance().queryPerriodDate(pk_accbook, year, period);

		sqlBuilder.append(" select b.pk_card from fa_alter h");
		sqlBuilder.append(" left outer join fa_alter_b b on h.pk_alter = b.pk_alter ");
		sqlBuilder.append(" where h.dr = 0 and b.dr = 0 ");
		sqlBuilder.append(" and h.business_date >= '" + periodVOs[0] + "'");
		sqlBuilder.append(" and h.business_date <= '" + periodVOs[1] + "'");
		sqlBuilder.append(" and h.pk_accbook = '" + pk_accbook + "'");
		sqlBuilder.append(" and h.transi_type = 'HG-04'");
		sqlBuilder.append(" and b.pk_card in ").append(InSqlManager.getInSQLValue(pk_cards));

		return (Set<String>) new BaseDAO().executeQuery(sqlBuilder.toString(), new ColumnSetProcessor<String>());
	}

	/**
	 * 实物传FA变动单
	 * 
	 * @see nc.itf.fa.prv.IAlter#queryAlterVOFromPAM(nc.pub.fa.msg.MsgVO)
	 */
	@Override
	public AlterVO queryAlterVOFromPAM(MsgVO msgVO) throws BusinessException {

		if (isExistByMsg(msgVO)) {
			ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
					"02012010-0070")/* @res "该消息已经生成了变动单！\n" */);
		}
		AlterVO billVO = MsgManager.queryPamByFA(msgVO);

		AlterHeadVO headVO = (AlterHeadVO) billVO.getParentVO();
		String bill_type_src = (String) headVO.getAttributeValue(AlterHeadVO.BILL_TYPE_SRC);

		AlterBodyVO[] bodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();

		headVO.setPk_accbook(FlagConsts.FLAG_NULL);
		headVO.setPk_org(msgVO.getPk_org());
		headVO.setPk_org_v(OrgUtils.getCurVidByPkOrg(msgVO.getPk_org()));
		headVO.setTransi_type(headVO.getTransi_type());
		headVO.setPk_group(msgVO.getPk_group());
		headVO.setBill_type_src(msgVO.getSrc_bill_type());
		headVO.setTransi_type_src(msgVO.getSrc_transi_type());

		// 查出【核算委托关系】中委托给当前财务主组织的业务单元
		Map<String, List<String>> pk_orgMapFromUAP = null;
		// 当前单据的主组织
		String pk_org = msgVO.getPk_org();
		try {
			pk_orgMapFromUAP = AMProxy.lookup(IOrgRelationDataPubService.class)
					.queryOrgUnitByPkFinanceorg(new String[] { pk_org });
		} catch (BusinessException e) {
			try {
				pk_orgMapFromUAP = null;
				String errMsg = nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("fapub_0",
						"02012000-0138")/*
										 * @ res "配置了核算委托关系，根据财务组织主键获取委托给它的业务单元失败！"
										 */;
				ExceptionUtils.asBusinessException(errMsg);
			} catch (BusinessException e2) {
				pk_orgMapFromUAP = null;
			}
		}

		// 对卡片加锁
		String[] pk_cards = VOManager.getAttributeValueArray(bodyVOs, AlterBodyVO.PK_CARD);

		Map<String, AssetVO> assetVOMap = MapUtils
				.toMap(AMProxy.lookup(IAssetService.class).queryMainAssetVOByPks(null, pk_cards));

		// 取得卡片对应的pk_equip
		String[] pk_equips = VOManager.getAttributeValueArray(CollectionUtils.toArray(assetVOMap.values()),
				AssetVO.PK_EQUIP);

		// 使用部门link_key
		String[] link_keys = VOManager.getAttributeValueArray(CollectionUtils.toArray(assetVOMap.values()),
				AssetVO.PK_USEDEPT);

		// 取得设备货主管理组织
		Map<String, EquipHeadVO> equipHeadVOMap = AMProxy.lookup(IEquipToFaService.class).queryEqVosByIds(pk_equips);

		// 实物传过来的是位置PK，不是名称

		List<String> pkLocationList = new ArrayList<String>();
		for (AlterBodyVO bodyVO : bodyVOs) {
			String pk_before = (String) bodyVO.getAttributeValue(AlterKeyConst.POSITION_BEFORE);
			if (StringUtils.isNotBlank(pk_before)) {
				pkLocationList.add(pk_before);
			}
			String pk_after = (String) bodyVO.getAttributeValue(AlterKeyConst.POSITION_AFTER);
			if (StringUtils.isNotBlank(pk_after)) {
				pkLocationList.add(pk_after);
			}
		}
		Map<String, String> locationPk2NameMap = null;
		if (CollectionUtils.isNotEmpty(pkLocationList)) {
			locationPk2NameMap = AMProxy.lookup(ILocationService.class)
					.queryLocationNameMap(CollectionUtils.toArray(pkLocationList));
		} else {
			locationPk2NameMap = Collections.emptyMap();
		}

		// 通过link_key得到对应的DeptScaleVO
		Map<String, List<DeptScaleVO>> deptScaleVOs = UseDeptScaleUtils.queryDeptScaleBatchWithDeptInfo(link_keys);

		// 记录卡片有变动项目的卡片，去掉没有变动的bodyVO
		List<AlterBodyVO> hasAlterItemBodyVOs = new ArrayList<AlterBodyVO>();

		// 通过OID取VID 管理部门
		String[] mandeptOIDs = VOManager.getAttributeValueArray(CollectionUtils.toArray(assetVOMap.values()),
				AssetFieldConst.PK_MANDEPT);
		HashMap<String, String> mandetpOidVids = AMProxy.lookup(IDeptPubService.class)
				.getLastVIDSByDeptIDS(mandeptOIDs);

		String[] checkItems = new String[] { AlterKeyConst.PK_MANDEPT, AlterKeyConst.PK_EQUIP_USEDEPT,
				AlterKeyConst.PK_EQUIP_ORG, AlterKeyConst.USEDEPT, AlterKeyConst.PK_ASSETUSER, AlterKeyConst.PK_USER,
				AlterKeyConst.POSITION, AlterKeyConst.PK_JOBMNGFIL, AlterKeyConst.PK_OWNERORG };

		// 额外处理变动项目
		for (AlterBodyVO bodyVO : bodyVOs) {
			// 用于备份VO对照之后的原始状态，借以判断来源单据的变动情况。
			// 非克隆的VO用于赋值。
			AlterBodyVO clonedBodyVO = CloneUtil.clone(bodyVO);

			String pk_card = bodyVO.getPk_card();
			AssetVO assetVO = assetVOMap.get(pk_card);
			String pk_equip = assetVO.getPk_equip();
			String equipOwnOrg = equipHeadVOMap.get(pk_equip).getPk_ownerorg();

			DeptScaleVO[] deptVOs = null;
			if (MapUtils.isNotEmpty(deptScaleVOs)) {
				deptVOs = CollectionUtils.toArray(deptScaleVOs.get(assetVO.getPk_usedept()));
			}
			AlterBodyVO cloneBodyVO = new AlterBodyVO();
			for (String item : checkItems) {
				String beforeKey = item + AlterKeyConst.BEFORE_SUFFIX;
				String afterKey = item + AlterKeyConst.AFTER_SUFFIX;
				cloneBodyVO.setAttributeValue(beforeKey, bodyVO.getAttributeValue(beforeKey));
				cloneBodyVO.setAttributeValue(afterKey, bodyVO.getAttributeValue(afterKey));
			}

			// 设置变动前管理部门
			bodyVO.setAttributeValue(AlterKeyConst.PK_MANDEPT_BEFORE, assetVO.getPk_mandept());

			// 设置变动前设备使用部门
			// String pk_equip_usedept_after = (String)
			// bodyVO.getAttributeValue(AlterKeyConst.PK_EQUIP_USEDEPT_AFTER);
			// 变动前设备使用部门直接取卡片里的值
			// String originEquipUsedeptBefore = (String)
			// bodyVO.getAttributeValue(AlterKeyConst.PK_EQUIP_USEDEPT_BEFORE);
			bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_USEDEPT_BEFORE, assetVO.getPk_equip_usedept());

			// 设置变动前使用权
			bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_ORG_BEFORE, assetVO.getPk_equiporg());
			bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_ORG_V_BEFORE, assetVO.getPk_equiporg_v());

			// 设置变动前货主管理组织
			bodyVO.setAttributeValue(AlterKeyConst.PK_OWNERORG_BEFORE, assetVO.getPk_ownerorg());
			bodyVO.setAttributeValue(AlterKeyConst.PK_OWNERORG_V_BEFORE, assetVO.getPk_ownerorg_v());
			// 变动后货主管理组织
			if (null == bodyVO.getAttributeValue(AlterKeyConst.PK_OWNERORG_AFTER)) {
				bodyVO.setAttributeValue(AlterKeyConst.PK_OWNERORG_AFTER, assetVO.getPk_ownerorg());
			}
			if (null == bodyVO.getAttributeValue(AlterKeyConst.PK_OWNERORG_V_AFTER)) {
				bodyVO.setAttributeValue(AlterKeyConst.PK_OWNERORG_V_AFTER, assetVO.getPk_ownerorg_v());
			}
			String pk_ownerorg_after = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_OWNERORG_AFTER);
			// 上游传递过来的“变动后货主管理组织”和当前主组织不同 且 该货主管理组织在【核算委托关系】中没有委托给当前财务组织
			if ((null != pk_org && null != pk_ownerorg_after && !pk_org.equals(pk_ownerorg_after))
					&& (pk_orgMapFromUAP == null || (pk_orgMapFromUAP != null
							&& !pk_orgMapFromUAP.get(pk_org).contains(pk_ownerorg_after)))) {
				ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
						"02012010-0085")/* @res "上游单据传递过来的“变动后货主管理组织”在【核算委托关系】中没有委托给当前财务组织！\n" */
				);
			}

			String useDeptBefore = (String) bodyVO.getAttributeValue(AlterKeyConst.USEDEPT_BEFORE);

			// 设置变动前使用部门
			bodyVO.setAttributeValue(AlterKeyConst.USEDEPT_BEFORE, DeptScaleManager.getShowVidName(deptVOs));
			// 变动前多使用部门缓存Key
			String pk_dept_before_key = FAUseDeptKeyGenerator.generatorKeyForAssetSplit(deptVOs);
			bodyVO.setAttributeValue(AlterBodyVO.PK_DEPT_BEFORE_KEY, pk_dept_before_key);
			bodyVO.setOld_deptscalevos(deptVOs);

			// 设置变动前使用人
			bodyVO.setAttributeValue(AlterKeyConst.PK_ASSETUSER_BEFORE, assetVO.getPk_assetuser());

			// 设置变动前责任人
			bodyVO.setAttributeValue(AlterKeyConst.PK_USER_BEFORE, assetVO.getPk_user());

			// 设置变动前位置
			bodyVO.setAttributeValue(AlterKeyConst.POSITION_BEFORE, assetVO.getPosition());

			// 设置变动前项目
			bodyVO.setAttributeValue(AlterKeyConst.PK_JOBMNGFIL_BEFORE, assetVO.getPk_jobmngfil());

			// 如果财务组织和货主管理组织不符，则不进行管理部门的变动
			// if (!headVO.getPk_org().equals(equipOwnOrg)) {
			// bodyVO.setAttributeValue(AlterKeyConst.PK_MANDEPT_V_AFTER,
			// assetVO.getPk_mandept_v());
			// } else {
			String pk_mandept_after = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_MANDEPT_V_AFTER);
			if (StringUtils.isEmpty(pk_mandept_after)) {
				pk_mandept_after = assetVO.getPk_mandept_v();
			}
			bodyVO.setAttributeValue(AlterKeyConst.PK_MANDEPT_V_AFTER, pk_mandept_after);
			// ncc端oid需要额外处理下
			if (!StringUtils.isEmpty(pk_mandept_after)) {
				HashMap<String, String> mandeptOids = AMProxy.lookup(IDeptPubService.class)
						.getOIDSByDeptVIDS(new String[] { pk_mandept_after });
				if (mandeptOids.get(pk_mandept_after) != null) {
					bodyVO.setAttributeValue(AlterKeyConst.PK_MANDEPT_AFTER, mandeptOids.get(pk_mandept_after));
				}
			}

			// }

			// 设置变动后使用权和使用部门
			String pk_equip_org_after = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_EQUIP_ORG_AFTER);
			/** modified by wangweiak 2015-01-29 不进行变动后使用权 和 变动单表头财务组织一致性判断，V636跨组织选部门新需求 */
			// if (headVO.getPk_org().equals(pk_equip_org_after)) {
			// if (true) {
			// || (headVO.getPk_org().equals(equipHeadVOMap.get(pk_equip).getPk_usedunit()))
			// 如果财务组织和使用权是同一个组织 或者 变动后的使用权 和财务组织一样，则进行FA卡片的管理部门的变动。
			// 当然即使一样，实物的单据可能没有对设备管理部门进行变动，此时固定资产不对管理部门进行变动。

			// 实物传过来的是PK值，并且只能是一个值
			String usedept_after = (String) bodyVO.getAttributeValue(AlterKeyConst.USEDEPT_AFTER);
			String pk_usedept_before = assetVO.getPk_usedept();
			List<DeptScaleVO> deptScaleBefore = new ArrayList<DeptScaleVO>();
			if (MapUtils.isNotEmpty(deptScaleVOs)) {
				deptScaleBefore = deptScaleVOs.get(pk_usedept_before);
			}

			// 如果有值才进行变动
			if (StringUtils.isNotBlank(usedept_after)) {
				// 变动前真正使用部门主键
				if (deptScaleBefore.size() == 1 && usedept_after.equals(useDeptBefore)) {
					bodyVO.setNew_deptscalevos(deptVOs);
					bodyVO.setAttributeValue(AlterKeyConst.USEDEPT_AFTER, DeptScaleManager.getShowName(deptVOs));
					// 变动后多使用部门缓存Key
					String pk_dept_after_key = FAUseDeptKeyGenerator.generatorKeyForAssetSplit(deptVOs);
					bodyVO.setAttributeValue(AlterBodyVO.PK_DEPT_AFTER_KEY, pk_dept_after_key);
				} else {
					DeptVO deptVO = ArrayUtils.getFirstElem(DeptScaleManager.queryDeptVO(usedept_after));
					if (deptVO != null) {
						DeptScaleVO scaleVO = new DeptScaleVO();
						String usedeptName = (String) deptVO
								.getAttributeValue(MultiLanguageUtil.getMultiNameField(DeptVO.NAME));
						// 如果当前语种取值为空，则取主语种的名称 by wangqsh
						if (usedeptName == null) {
							usedeptName = (String) deptVO.getAttributeValue(DeptVO.NAME);
						}
						scaleVO.setDeptName(usedeptName);
						scaleVO.setPk_dept(deptVO.getPk_dept());
						scaleVO.setUsescale(new UFDouble(100));
						DeptScaleVO[] insertedVO = AMProxy.lookup(IUseDeptScaleService.class)
								.insert(new DeptScaleVO[] { scaleVO });
						bodyVO.setAttributeValue(AlterKeyConst.USEDEPT_AFTER, usedeptName);
						// 变动后多使用部门缓存Key
						String pk_dept_after_key = FAUseDeptKeyGenerator.generatorKeyForAssetSplit(insertedVO);
						bodyVO.setAttributeValue(AlterBodyVO.PK_DEPT_AFTER_KEY, pk_dept_after_key);
						bodyVO.setNew_deptscalevos(insertedVO);
					}
				}
			}
			// } else {
			// // 如果不是相同的使用权
			// String usedept_after = (String)
			// bodyVO.getAttributeValue(AlterKeyConst.USEDEPT_BEFORE);
			// bodyVO.setAttributeValue(AlterKeyConst.USEDEPT_AFTER, usedept_after);
			// bodyVO.setNew_deptscalevos(bodyVO.getOld_deptscalevos());
			//
			// String pk_assetuser_after = (String)
			// bodyVO.getAttributeValue(AlterKeyConst.PK_ASSETUSER_BEFORE);
			// bodyVO.setAttributeValue(AlterKeyConst.PK_ASSETUSER_AFTER,
			// pk_assetuser_after);
			// }

			// 由于有些实物的单据不会将所有的变动后的值都传过来，所以这里需要判断：如果经过处理的变动后为null，则表示没有进行变动。
			// 管理部门
			pk_mandept_after = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_MANDEPT_V_AFTER);

			if (StringUtils.isBlank(pk_mandept_after)) {
				pk_mandept_after = assetVO.getPk_mandept_v();
				bodyVO.setAttributeValue(AlterKeyConst.PK_MANDEPT_V_AFTER, pk_mandept_after);
			}
			// 使用前手动塞值
			bodyVO.setAttributeValue(AlterKeyConst.PK_MANDEPT_V_BEFORE, assetVO.getPk_mandept_v());

			// 使用部门
			String tusedept_after = (String) bodyVO.getAttributeValue(AlterKeyConst.USEDEPT_AFTER);
			if (StringUtils.isBlank(tusedept_after)) {
				tusedept_after = (String) bodyVO.getAttributeValue(AlterKeyConst.USEDEPT_BEFORE);
				bodyVO.setAttributeValue(AlterKeyConst.USEDEPT_AFTER, tusedept_after);
				bodyVO.setNew_deptscalevos(bodyVO.getOld_deptscalevos());
			}

			// 变动后使用人
			String pk_assetuser_after = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_ASSETUSER_AFTER);
			// 资产闲置不会涉及固定资产卡片上“使用人”的变动，直接取卡片上的使用人即可
			if (BillTypeConst_4A.unused.equals(bill_type_src)) {
				bodyVO.setAttributeValue(AlterKeyConst.PK_ASSETUSER_AFTER, assetVO.getPk_assetuser());
			} else {
				if (StringUtils.isEmpty(pk_assetuser_after)) {
					// 来源单据不涉及“使用人”的变动。
					if (!hasValueAltered(clonedBodyVO, AlterKeyConst.PK_ASSETUSER)) {
						if (null != assetVO.getPk_assetuser()) {
							bodyVO.setAttributeValue(AlterKeyConst.PK_ASSETUSER_AFTER, assetVO.getPk_assetuser());
						}
					} // 来源单据变动了“使用人”。
					else {
						bodyVO.setAttributeValue(AlterKeyConst.PK_ASSETUSER_AFTER, pk_assetuser_after);
					}
					// bodyVO.setAttributeValue(AlterKeyConst.PK_ASSETUSER_AFTER,
					// assetVO.getPk_assetuser());
				}
			}
			bodyVO.setAttributeValue(AlterKeyConst.PK_ASSETUSER_BEFORE, assetVO.getPk_assetuser());
			// 变动后责任人
			// String pk_user_after = (String)
			// bodyVO.getAttributeValue(AlterKeyConst.PK_USER_AFTER);
			// if (StringUtils.isEmpty(pk_user_after)) {
			// // 来源单据不涉及“责任人”的变动。
			// if (!hasValueAltered(clonedBodyVO, AlterKeyConst.PK_USER)) {
			// if (null != assetVO.getPk_user()) {
			// bodyVO.setAttributeValue(AlterKeyConst.PK_USER_AFTER, assetVO.getPk_user());
			// }
			// } // 来源单据变动了“责任人”。
			// else {
			// bodyVO.setAttributeValue(AlterKeyConst.PK_USER_AFTER, pk_user_after);
			// }
			// } else {
			// bodyVO.setAttributeValue(AlterKeyConst.PK_USER_AFTER, pk_user_after);
			// }

			// 变动后使用位置
			String position_after = (String) bodyVO.getAttributeValue(AlterKeyConst.POSITION_AFTER);
			if (StringUtils.isNotEmpty(position_after)) {
				bodyVO.setAttributeValue(AlterKeyConst.POSITION_AFTER, locationPk2NameMap.get(position_after));
			} else {
				// bodyVO.setAttributeValue(AlterKeyConst.POSITION_AFTER,
				// assetVO.getPosition());
			}
			bodyVO.setAttributeValue(AlterKeyConst.POSITION_BEFORE, assetVO.getPosition());
			// 来源单据变动了“使用位置”。
			// 位置档案通过“名称”判断是否发生变动。
			if (hasValueAltered(bodyVO, AlterKeyConst.POSITION)) {
				hasAlterItemBodyVOs.add(bodyVO);
			}

			// 变动后项目
			String jobproject_after = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_JOBMNGFIL_AFTER);
			if (StringUtils.isEmpty(jobproject_after)) {
				// 来源单据不涉及“项目”的变动。
				if (!hasValueAltered(clonedBodyVO, AlterKeyConst.PK_JOBMNGFIL)) {
					bodyVO.setAttributeValue(AlterKeyConst.PK_JOBMNGFIL_AFTER, assetVO.getPk_jobmngfil());
				} // 来源单据变动了“项目”。
				else {
					bodyVO.setAttributeValue(AlterKeyConst.PK_JOBMNGFIL_AFTER, jobproject_after);
				}
			} else {
				bodyVO.setAttributeValue(AlterKeyConst.PK_JOBMNGFIL_AFTER, jobproject_after);
			}
			bodyVO.setAttributeValue(AlterKeyConst.PK_JOBMNGFIL_BEFORE, assetVO.getPk_jobmngfil());
			// 变动后使用权
			String equipOrgAfterValue = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_EQUIP_ORG_AFTER);
			String equipOrgBeforeValue = (String) cloneBodyVO.getAttributeValue(AlterKeyConst.PK_EQUIP_ORG_BEFORE);
			if (StringUtils.isEmpty(equipOrgAfterValue) && StringUtils.isEmpty(equipOrgBeforeValue)) {
				bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_ORG_AFTER, assetVO.getPk_equiporg());
				bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_ORG_V_AFTER, assetVO.getPk_equiporg_v());
			} else if (StringUtils.isEmpty(equipOrgBeforeValue) && StringUtils.isNotEmpty(equipOrgAfterValue)) {
				bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_ORG_AFTER, equipOrgAfterValue);
			} else {
				if (!equipOrgBeforeValue.equals(equipOrgAfterValue)) {
					bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_ORG_AFTER, equipOrgAfterValue);
				}
			}
			bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_ORG_BEFORE, assetVO.getPk_equiporg());
			bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_ORG_V_BEFORE, assetVO.getPk_equiporg_v());
			// 固定资产卡片的“变动前设备使用部门”和来源单据的“变动后设备使用部门”比较。
			// String equipUsedeptAfter = (String)
			// bodyVO.getAttributeValue(AlterKeyConst.PK_EQUIP_USEDEPT_AFTER);
			// // String equipUsedeptBefore = (String)
			// bodyVO.getAttributeValue(AlterKeyConst.PK_EQUIP_USEDEPT_BEFORE);
			// if ((StringUtils.isEmpty(equipUsedeptAfter) &&
			// StringUtils.isEmpty(originEquipUsedeptBefore))
			// || (StringUtils.isNotEmpty(equipUsedeptAfter)
			// && StringUtils.isNotEmpty(originEquipUsedeptBefore)
			// && equipUsedeptAfter.equals(originEquipUsedeptBefore))) {
			// // bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_USEDEPT_AFTER,
			// assetVO.getPk_equip_usedept());
			// } // 来源单据变动了“设备使用部门”。
			// else {
			// bodyVO.setAttributeValue(AlterKeyConst.PK_EQUIP_USEDEPT_AFTER,
			// pk_equip_usedept_after);
			// }

			// 过滤没有变动项的VO
			boolean isHasAlter = filterHasNotAlterItemBodyVO(bodyVO, mandetpOidVids, checkItems);
			if (isHasAlter && hasNotAddCurrentBody(hasAlterItemBodyVOs, bodyVO)) {
				hasAlterItemBodyVOs.add(bodyVO);
			} else {
				continue;
			}
		}

		if (hasAlterItemBodyVOs.size() == 0) {
			ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
					"02012010-0080")/* @res "没有发生任何变动，请检查来源单据的操作是否造成固定资产变动。\n" */);
		} else {
			billVO.setChildrenVO(null);
			billVO.setChildrenVO(hasAlterItemBodyVOs.toArray(new AlterBodyVO[0]));
		}

		return billVO;
	}

	/**
	 * <p>
	 * 判断指定项目是否有变动。
	 * 
	 * @param bodyVO
	 * @param itemCode
	 * @return
	 */
	private boolean hasValueAltered(AlterBodyVO bodyVO, String itemCode) {

		boolean result = false;

		// 参数非空。
		if (bodyVO != null && StringUtils.isNotEmpty(itemCode + AlterKeyConst.BEFORE_SUFFIX)
				&& StringUtils.isNotEmpty(itemCode + AlterKeyConst.AFTER_SUFFIX)) {
			// 取得变动前、变动后的值。
			Object bodyValueBefore = bodyVO.getAttributeValue(itemCode + AlterKeyConst.BEFORE_SUFFIX);
			Object bodyValueAfter = bodyVO.getAttributeValue(itemCode + AlterKeyConst.AFTER_SUFFIX);
			// 变动前空、变动后非空。
			if ((bodyValueBefore == null && bodyValueAfter != null)
					// 变动前非空、变动后空。
					|| (bodyValueBefore != null && bodyValueAfter == null)
					// 变动前非空、变动后非空，且二者不等。
					|| ((bodyValueBefore != null && bodyValueAfter != null)
							&& !(bodyValueBefore.equals(bodyValueAfter)))) {
				result = true;
			}
		}

		return result;
	}

	/**
	 * <p>
	 * 判断指定的表体是否已经被置入列表中。<br>
	 * 由于特殊处理设备卡片上的“位置”信息，所以有可能因为位置变动而将当前表体提前置入过列表了。
	 * 
	 * @param hasAlterItemBodyVOs
	 * @param bodyVO
	 * @return
	 */
	private boolean hasNotAddCurrentBody(List<AlterBodyVO> hasAlterItemBodyVOs, AlterBodyVO bodyVO) {

		boolean hasNotAddCurrentBody = true;

		if (hasAlterItemBodyVOs != null && !hasAlterItemBodyVOs.isEmpty() && bodyVO != null) {
			for (AlterBodyVO hasAlterItemBodyVO : hasAlterItemBodyVOs) {
				if (hasAlterItemBodyVO.getPk_card().equals(bodyVO.getPk_card())) {
					hasNotAddCurrentBody = false;
					break;
				}
			}
		}

		return hasNotAddCurrentBody;
	}

	/**
	 * 
	 * 过滤没有变动项的VO
	 * <p>
	 * 
	 * @author weizq
	 * @param mandetpOidVids
	 * @param checkItems2
	 * @time 2011-11-24 下午03:32:34
	 */
	private boolean filterHasNotAlterItemBodyVO(AlterBodyVO bodyVO, HashMap<String, String> mandetpOidVids,
			String[] checkItems) {

		boolean isHasAlter = false;
		for (String item : checkItems) {
			EqualsBuilder eb = new EqualsBuilder();

			// 单独处理管理部门
			if (item.equals(AlterKeyConst.PK_MANDEPT)) {
				String mandeptBefore = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_MANDEPT_BEFORE);
				String mandeptAfter = (String) bodyVO.getAttributeValue(AlterKeyConst.PK_MANDEPT_V_AFTER);

				if (StringUtils.isNotEmpty(mandeptBefore) && StringUtils.isNotEmpty(mandeptAfter)) {
					// 取VID的管理部门进行比较
					mandeptBefore = mandetpOidVids.get(mandeptBefore);
				}

				eb.append(mandeptBefore, mandeptAfter);
				if (!eb.isEquals()) {
					isHasAlter = true;
					break;
				}
			}

			// else if (item.equals(AlterKeyConst.POSITION)) {
			// 此处位置已经更新为名称，无法比较主键了。
			// 所以校验在方法外设置名称值之前执行。
			// }
			else {
				Object beforeValue = bodyVO.getAttributeValue(item + AlterKeyConst.BEFORE_SUFFIX);
				Object afterValue = bodyVO.getAttributeValue(item + AlterKeyConst.AFTER_SUFFIX);

				if (AlterKeyConst.USEDEPT.equals(item)) {
					beforeValue = StringUtils.toString(bodyVO.getAttributeValue(AlterBodyVO.PK_DEPT_BEFORE_KEY));
					afterValue = StringUtils.toString(bodyVO.getAttributeValue(AlterBodyVO.PK_DEPT_AFTER_KEY));
					// 如果变动后使用部门为空，则默认处理为不变动，因为固定资产使用部门为必填
					if (afterValue == null || "".equals(afterValue)) {
						afterValue = beforeValue;
					}
				}

				eb.append(beforeValue, afterValue);
				if (!eb.isEquals()) {
					isHasAlter = true;
					break;
				}
			}
		}

		return isHasAlter;
	}

	@Override
	public AlterVO[] queryAlterVOByPKs(String... pks) throws BusinessException {

		return queryAlterVOByPKs(pks, false);
	}

	@Override
	public AlterVO[] queryFullAlterVOByPKs(String... pks) throws BusinessException {

		AlterHeadVO[] headVOs = (AlterHeadVO[]) VOManager.getHeadVOs(queryAlterVOByPKs(pks));

		List<AlterVO> alterVOs = new ArrayList<AlterVO>();
		if (ArrayUtils.isNotEmpty(headVOs)) {
			for (AlterHeadVO headVO : headVOs) {
				AlterVO alterVO = new AlterVO();
				alterVO.setParent(headVO);
				alterVO.setChildrenVO(queryAlterBodyVOs(headVO.getPk_alter(), headVO.getPk_accbook()));
				alterVOs.add(alterVO);
			}
		}

		return alterVOs.toArray(new AlterVO[0]);
	}

	/**
	 * 根据变动单表头PK查询其孙表的所有记录
	 * 
	 * @param pk_alter
	 * @return
	 * @throws BusinessException
	 * @date 2010-5-10
	 */
	public AlterSheetVO[] queryAlterSheetVOByBillPk(String pk_alter) throws BusinessException {

		String sql = " dr =0 and pk_alter = '" + pk_alter + "' ";
		return QueryUtil.queryVOByCond(AlterSheetVO.class, sql, null);
	}

	public Map<String, List<AlterSheetVO>> queryAlterSheetVOByBillPKs(String... pk_alters) throws BusinessException {

		String sql = " select pk_alter,item_code, old_content, new_content, altertype from fa_altersheet where dr =0 and pk_alter in "
				+ InSqlManager.getInSQLValue(pk_alters);

		BeanListMapProcessor<AlterSheetVO> p = new BeanListMapProcessor<AlterSheetVO>(AlterSheetVO.PK_ALTER,
				AlterSheetVO.class);

		return new DBAccessUtil().executeQuery(sql, p);
	}

	public Map<String, List<AlterSheetVO>> queryAlterSheetVOByBodyPKs(String... bodyPKs) throws BusinessException {

		String sql = " select pk_alter_b,item_code, old_content, new_content, local_differ, differ, altertype  from fa_altersheet where dr =0 and pk_alter_b in "
				+ InSqlManager.getInSQLValue(bodyPKs);

		BeanListMapProcessor<AlterSheetVO> p = new BeanListMapProcessor<AlterSheetVO>(AlterSheetVO.PK_ALTER_B,
				AlterSheetVO.class);

		return new DBAccessUtil().executeQuery(sql, p);
	}

	/**
	 * 根据变动单表头PK查询其子表的所有记录，可能会包含'~'和具体财务账簿的表体数据
	 * 
	 * @param pk_alter
	 * @return
	 * @throws BusinessException
	 * @date 2010-5-10
	 */
	public AlterBodyVO[] queryAlterBodyVOByBillPk(String pk_alter) throws BusinessException {

		String sql = " dr =0 and pk_alter = '" + pk_alter + "' ";
		return QueryUtil.queryVOByCond(AlterBodyVO.class, sql, null);
	}

	/**
	 * 由于现在在单账簿下减少后，还能在业务账簿下减少其他账簿的数据，因此需要按未被减少的账簿进行分批更新卡片日志。
	 * 
	 * @param billVO
	 * @param isDelete 是否删除单据
	 * @throws BusinessException
	 * @date 2010-5-17
	 */
	private void updateCardLog(String pk_accbook, String bill_code, String bill_type, Integer bill_status,
			String[] pk_cards) throws BusinessException {

		// Map<pk_accbook,List<pk_card>>将相同账簿的卡片弄在一起。目的是为了按账簿进行分批更新
		Map<String, List<String>> accbookToCardMap = new HashMap<String, List<String>>();
		// 表体所有的卡片
		// 如果是业务账簿
		if (AccbookManager.isBizAccbook(pk_accbook)) {
			// Map<pk_accbook,List<pk_card>>卡片没有被减少的账簿
			accbookToCardMap = AMProxy.lookup(IAssetService.class).queryNotReducedAccbookToCardMap(pk_cards);
		} else {
			// 只需对一个财务账簿进行更新
			accbookToCardMap.put(pk_accbook, Arrays.asList(pk_cards));
		}

		// 分账簿对卡片单据号进行更新
		for (Map.Entry<String, List<String>> entry : accbookToCardMap.entrySet()) {
			getLogService().updateLog(entry.getKey(), CollectionUtils.toArray(entry.getValue()), bill_code, bill_type,
					bill_status);
		}
	}

	/**
	 * 查询表体中的所有卡片PK
	 * 
	 * @param parentPK
	 * @param pk_accbook
	 * @return
	 * @throws DAOException
	 * @date 2010-5-17
	 */
	@SuppressWarnings("unchecked")
	private String[] queryBodyCardId(String parentPK, String pk_accbook) throws DAOException {

		String sql = "select pk_card from fa_alter_b where dr= 0 and pk_alter = '" + parentPK + "' and pk_accbook = '"
				+ AccbookManager.getValidAccbook(pk_accbook) + "'";
		Set<String> set = (Set<String>) new DBAccessUtil().executeQuery(sql, new ColumnSetProcessor<String>());
		return CollectionUtils.toArray(set);
	}

	/**
	 * 根据来源单据ID，判断该单据生成的变动单是否存在
	 * 
	 * @param pk_bill_src
	 * @return
	 * @throws DAOException
	 * @date 2010-5-19
	 */
	protected boolean isExistBySrcBillPk(String pk_bill_src) throws BusinessException {

		String sql = " select top 1 '1' from fa_alter where dr = 0 and pk_bill_src = ?";
		SQLParameter params = new SQLParameter();
		params.addParam(pk_bill_src);
		return ((Boolean) new DBAccessUtil().executeQuery(sql, params, new BooleanProcessor())).booleanValue();
	}

	/**
	 * 跟据单据主键和财务组织判断是否做过变动
	 * 
	 * @param pk_bill_src
	 * @return
	 * @throws DAOException
	 * @date 2010-5-19
	 */
	protected boolean isExistByMsg(MsgVO msgVO) throws BusinessException {

		StringBuffer sqlBuff = new StringBuffer();
		sqlBuff.append(" select top 1 '1' ").append("   from fa_alter ").append("  where dr = 0 ")
				.append("    and pk_bill_src = ? ").append("    and transi_type = ? ").append("    and pk_org = ? ");
		SQLParameter params = new SQLParameter();
		params.addParam(msgVO.getSrc_billid());
		params.addParam(msgVO.getDest_transi_type());
		params.addParam(msgVO.getPk_org());

		return ((Boolean) new DBAccessUtil().executeQuery(sqlBuff.toString(), params, new BooleanProcessor()))
				.booleanValue();
	}

	@Override
	public Map<String, TraceResultVO> handlerTrace(UFBoolean check, TraceVO... traceVOs) throws BusinessException {

		return TraceManager.trace(check, traceVOs);
	}

	/**
	 * 工单-----资本化调整
	 */
	@Override
	public AlterVO queryAlterVOFromWorkOrder(MsgVO msgVO) throws BusinessException {

		// 查询消息中上游单据的接口
		Object serviceObject = AMProxy.lookup(msgVO.getService_class_name());

		AlterVO destVO = null;
		try {
			// 通过PK查出工单VO
			AMSuperVO workOrderHeadVO = (AMSuperVO) MethodUtils.invokeMethod(serviceObject, msgVO.getMethod_name(),
					new Object[] { msgVO.getSrc_billid() });

			// 工单中的设备主键
			String pk_equip = (String) workOrderHeadVO.getAttributeValue(CommonKeyConst.pk_equip);
			// 资本化设备
			String pk_equip_capital = (String) workOrderHeadVO.getAttributeValue(IWorkOrderFields.PK_EQUIP_CAPITAL);

			// 查询工单关联的设备VO
			Map<String, EquipHeadVO> equipHeadVOMap = AMProxy.lookup(IEquipToFaService.class)
					.queryEqVosByIds(new String[] { pk_equip, pk_equip_capital });
			EquipHeadVO equipHeadVO = equipHeadVOMap.get(pk_equip);
			EquipHeadVO equipHeadVO1 = equipHeadVOMap.get(pk_equip_capital);
			// 固定资产卡片
			String pk_card = equipHeadVO.getPk_card();
			// 如果主设备未关联固定资产，则从资本化设备中取固定资产卡片
			if (null == pk_card) {
				pk_card = equipHeadVO1.getPk_card();
			}

			if (StringUtils.isEmpty(pk_card)) {
				ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
						"02012010-0072")/* @res "没有此固定资产卡片，请检查.  \n " */);
			}
			// 查询主账簿卡片数据
			AssetVO[] cardVOs = AMProxy.lookup(IAssetService.class).queryMainAssetVOByPks(null, pk_card);
			AssetVO mainAccbookCardVO = ArrayUtils.isNotEmpty(cardVOs) ? cardVOs[0] : null;

			if (mainAccbookCardVO != null) {
				msgVO.setPk_org(mainAccbookCardVO.getPk_org());
			}
			if (isExistByMsg(msgVO)) {
				ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
						"02012010-0071")/* @res "该消息已经生成了变动单. \n" */);
			}

			if (mainAccbookCardVO == null || !mainAccbookCardVO.getAsset_state().equals(AssetStateConst.exist)) {
				ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0",
						"02012010-0073")/* @res "该组织下的卡片不存在， 可能已经被减少, 请检查  \n " */);
			} else {
				// 将工单VO转化成变动VO
				destVO = convertToAlterVOByWorkOrder(workOrderHeadVO, pk_card, mainAccbookCardVO);
			}
		} catch (Exception e) {
			Debug.error(e.getMessage());
			ExceptionUtils.asBusinessException(e);
		}

		return destVO;
	}

	/**
	 * 将工单VO转化成变动VO
	 * 
	 * @param workOrderHeadVO
	 * @param pk_card
	 * @param mainAccbookCardVO
	 * @return
	 * @throws BusinessException
	 */
	private static AlterVO convertToAlterVOByWorkOrder(AMSuperVO workOrderHeadVO, String pk_card,
			AssetVO mainAccbookCardVO) throws BusinessException {

		String pk = workOrderHeadVO.getPrimaryKey();

		// 实际总成本 就是资本化成本
		UFDouble captionValue = (UFDouble) workOrderHeadVO.getAttributeValue("ac_ttl_mny_org");
		// 工单的本位币
		String pk_currtype = (String) workOrderHeadVO.getAttributeValue("pk_currtype");

		AlterVO billVO = new AlterVO();
		AlterHeadVO headVO = new AlterHeadVO();
		headVO.setPk_bill_src(pk);
		headVO.setPk_accbook(mainAccbookCardVO.getPk_accbook());
		headVO.setPk_org(mainAccbookCardVO.getPk_org());
		headVO.setPk_org_v(OrgUtils.getCurVidByPkOrg(mainAccbookCardVO.getPk_org()));
		headVO.setTransi_type(AlterTransiTypeConst.Value);
		headVO.setBill_status(BillStatusConst.free_check);
		headVO.setBill_type(BillTypeConst_FA.ALTER);
		headVO.setBill_type_src(BillTypeConst_4B.WORKORDER);
		headVO.setTransi_type_src((String) workOrderHeadVO.getAttributeValue(AssetFieldConst.TRANSI_TYPE));
		headVO.setBusiness_date(BizContext.getInstance().getBizDate());
		headVO.setPk_group(mainAccbookCardVO.getPk_group());

		List<AlterBodyVO> bodyVOs = new ArrayList<AlterBodyVO>();
		AlterBodyVO bodyVO = new AlterBodyVO();
		bodyVO.setPk_currency(mainAccbookCardVO.getPk_currency());
		bodyVO.setPk_card(pk_card);
		bodyVO.setPk_bill_b_src(pk);
		bodyVO.setPk_bill_src(pk);
		bodyVO.setPk_accbook(mainAccbookCardVO.getPk_accbook());

		captionValue = CurrencyRateManager.getAccbookAmountByOpp(mainAccbookCardVO.getPk_accbook(), pk_currtype,
				captionValue, headVO.getBusiness_date());

		// 本币原值
		bodyVO.setAttributeValue(AlterKeyConst.LOCALORIGINVALUE_ALTER, captionValue);
		bodyVO.setAttributeValue(AlterKeyConst.LOCALORIGINVALUE_BEFORE, mainAccbookCardVO.getLocaloriginvalue());
		bodyVO.setAttributeValue(AlterKeyConst.LOCALORIGINVALUE_AFTER,
				UFDoubleUtils.add(captionValue, mainAccbookCardVO.getLocaloriginvalue()));

		// 变动前净残值
		bodyVO.setAttributeValue(AlterKeyConst.SALVAGE_BEFORE, mainAccbookCardVO.getSalvage());
		// 变动后净残值
		UFDouble after_salvage = UFDoubleUtils
				.multiply((UFDouble) bodyVO.getAttributeValue(AlterKeyConst.LOCALORIGINVALUE_AFTER),
						mainAccbookCardVO.getSalvagerate())
				.div(100);
		bodyVO.setAttributeValue(AlterKeyConst.SALVAGE_AFTER, after_salvage);
		// 变动部分
		bodyVO.setAttributeValue(AlterKeyConst.SALVAGE_ALTER,
				UFDoubleUtils.sub(after_salvage, mainAccbookCardVO.getSalvage()));

		bodyVO.setAttributeValue(AlterKeyConst.SALVAGERATE_BEFORE, mainAccbookCardVO.getSalvagerate());
		bodyVO.setAttributeValue(AlterKeyConst.SALVAGERATE_AFTER, mainAccbookCardVO.getSalvagerate());
		bodyVOs.add(bodyVO);

		billVO.setParentVO(headVO);
		billVO.setChildrenVO(bodyVOs.toArray(new AlterBodyVO[0]));

		return billVO;
	}

	/**
	 * 根据外部模块(现在是项目管理)的消息生成价值调整或者资产追溯调整
	 */
	@Override
	public AlterVO queryAlterVOFromOtherModule(MsgVO msgVO) throws BusinessException {

		// 1. 校验该消息是否生成变动单
		if (isExistByMsg(msgVO)) {
			// 该消息已经生成了变动单.
			ExceptionUtils.asBusinessException(
					nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0", "02012010-0071"));
		}

		/*
		 * 2. VO对照
		 */
		// 查询消息中上游单据的接口
		Object serviceObject = AMProxy.lookup(msgVO.getService_class_name());
		AlterVO destVO = null;
		try {
			/** modified by wangweiak 2014-07-17 适配港华专项项目成本转固单生成本币原值调整单 */
			// 根据成本转固单主键调接口查询出成本转固单的VO
			AggregatedValueObject[] srcVOs;
			// 增加分支专项处理【项目成本转固单】发【本币原值调整单】消息
			if (BillTypeOther.cbs_project.equals(msgVO.getSrc_bill_type())) {
				srcVOs = new AggregatedValueObject[1];
				srcVOs[0] = NCLocator.getInstance().lookup(ICostToFixedBillQuery.class)
						.getCostToFixedAggvoByPk(msgVO.getSrc_billid());
				if (null == srcVOs[0]) {
					// 来源的数据为空, 请检查 \n
					ExceptionUtils.asBusinessException(
							nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("facard_0", "02012005-0488"));
				}
			} else { // 原有其他消息VO处理
				srcVOs = (AggregatedValueObject[]) MethodUtils.invokeMethod(serviceObject, msgVO.getMethod_name(),
						new Object[] { new String[] { msgVO.getSrc_billid() }, msgVO.getDest_transi_type() });
			}
			if (ArrayUtils.isEmpty(srcVOs)) {
				// 来源的数据为空, 请检查 \n
				ExceptionUtils.asBusinessException(
						nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("facard_0", "02012005-0488"));
			}

			AggregatedValueObject[] retVOs;
			// 增加分支专项处理【项目成本转固单】发【本币原值调整单】消息
			if (BillTypeOther.cbs_project.equals(msgVO.getSrc_bill_type())) {
				// 项目成本转固单--工程转固单 VO对照
				retVOs = PfUtilToolsAM.runChangeDataAryWithItfDef(BillTypeOther.cbs_project, BillTypeConst_FA.ALTER,
						srcVOs);
			} else { // 原有其他消息VO处理

				// 上游单据VO对照到下游单据VO (现在对照关心内容: 卡片主键，表体币种,来源单据主键, 来源单据类型,来源交易类型,
				// 目的交易类型, 调整金额等)
				retVOs = PfUtilToolsFA.runChangeDataAryWithItfDef(msgVO.getDest_bill_type(),
						msgVO.getDest_transi_type(), srcVOs);
			}
			/** end */

			/*
			 * 3. 处理变动部分值，币种折算
			 */
			// 返回第一个元素值, 只能是一个消息一个单据, 所以只会存在1个
			destVO = (AlterVO) ArrayUtils.getFirstElem(retVOs);

			// added by wangweiak 2015-02-04
			// 特殊处理工单中主设备中没有关联固定资产卡片，子设备关联固定资产卡片时，做工单资本化的需求。工单的单据类型为“4B36”
			if (BillTypeConst_4B.WORKORDER.equals(msgVO.getSrc_bill_type())) {
				// 工单中的设备主键
				String pk_equip = (String) srcVOs[0].getParentVO().getAttributeValue(CommonKeyConst.pk_equip);
				// 资本化设备
				String pk_equip_capital = (String) srcVOs[0].getParentVO()
						.getAttributeValue(IWorkOrderFields.PK_EQUIP_CAPITAL);
				// 查询工单关联的设备VO
				Map<String, EquipHeadVO> equipHeadVOMap = AMProxy.lookup(IEquipToFaService.class)
						.queryEqVosByIds(new String[] { pk_equip, pk_equip_capital });
				EquipHeadVO equipHeadVO = equipHeadVOMap.get(pk_equip);
				EquipHeadVO equipHeadVO1 = equipHeadVOMap.get(pk_equip_capital);
				// 固定资产卡片
				String pk_card = equipHeadVO.getPk_card();
				// 如果主设备未关联固定资产，则从资本化设备中取固定资产卡片
				if (null == pk_card) {
					pk_card = equipHeadVO1.getPk_card();
				}
				AlterBodyVO[] alterBodyVO = (AlterBodyVO[]) destVO.getChildrenVO();
				alterBodyVO[0].setPk_card(pk_card); // 不存在批量的情况
			}
			/** end */

			// 过滤不是当前财务组织的卡片
			filterCardByPkOrg(destVO, msgVO);
			// 过滤固定资产模块中已经做过减少业务的卡片。
			filterReducedAsset(destVO);
			// 处理传过来的金额，根据币种折算
			dealWithVOComparisonAfterByOtherModule(destVO);
		} catch (InvocationTargetException ite) {
			if (StringUtils.isEmpty(ite.getMessage()) && ite.getCause() != null) {
				Debug.debug(ite.getCause().getMessage());
				ExceptionUtils.asBusinessException(ite.getCause());
			}
		} catch (Exception e) {
			Debug.debug(e.getMessage());
			ExceptionUtils.asBusinessException(e);
		}

		return destVO;
	}

	/**
	 * <p>
	 * 过滤含有已经被减少的卡片的表体。
	 * 
	 * @param vo
	 * @throws BusinessException
	 */
	private void filterReducedAsset(AlterVO vo) throws BusinessException {

		if (vo != null) {
			List<AlterBodyVO> newAlterBodyVOs = getAlterBodysWithExistAsset(vo);

			if (newAlterBodyVOs != null && !newAlterBodyVOs.isEmpty()) {
				vo.setChildrenVO(newAlterBodyVOs.toArray(new AlterBodyVO[] {}));
			}
		}
	}

	/**
	 * <p>
	 * 取得含有未减少卡片的表体。
	 * 
	 * @param vo
	 * @return
	 * @throws BusinessException
	 */
	private List<AlterBodyVO> getAlterBodysWithExistAsset(AlterVO vo) throws BusinessException {

		List<AlterBodyVO> alterBodysWithExistAsset = new ArrayList<AlterBodyVO>();

		AlterBodyVO[] bodys = (AlterBodyVO[]) vo.getChildrenVO();

		if (ArrayUtils.isNotEmpty(bodys)) {
			// 取得表体所有资产卡片是否减少的判断结果。
			String[] pk_cards = VOManager.getAttributeValueArray(bodys, AssetFieldConst.PK_CARD);
			Map<String, Boolean> reducedAsset = AMProxy.lookup(IReduceService.class).isCardReduced(pk_cards);

			// 取得含有未减少卡片的表体。
			for (AlterBodyVO body : bodys) {
				if (!reducedAsset.get(body.getPk_card())) {
					alterBodysWithExistAsset.add(body);
				}
			}
		}

		return alterBodysWithExistAsset;
	}

	private void filterCardByPkOrg(AlterVO billVO, MsgVO msgVO) throws BusinessException {

		AlterBodyVO[] bodyVOs = (AlterBodyVO[]) billVO.getChildrenVO();
		List<String> pk_cardList = new ArrayList<String>();

		// // 去掉没有关联固定资产卡片的表体
		for (SuperVO bodyVO : bodyVOs) {
			String pk_card = (String) bodyVO.getAttributeValue(CommonKeyConst.pk_card);
			if (StringUtils.isNotBlank(pk_card)) {
				if (pk_card.contains(":")) {
					String[] pk_cards = pk_card.split(":");
					for (int i = 0; i < pk_cards.length; i++) {
						pk_cardList.add(pk_cards[i]);
					}
				} else {
					pk_cardList.add(pk_card);
				}
			}
		}

		if (pk_cardList.size() == 0) {
			ExceptionUtils.asBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("facard_0",
					"02012005-0489")/* @res "卡片有可能被删除，请检查 \n " */);
		}

		// 过滤掉不属于MsgVO.getPk_org()组织的卡片
		Set<String> pk_cardSet = new HashSet<String>();
		String[] filterCardIds = AMProxy.lookup(IAssetService.class).filterOrgCards(msgVO.getPk_org(),
				CollectionUtils.toArray(pk_cardList));
		Collections.addAll(pk_cardSet, filterCardIds);

		List<SuperVO> newBodyList = new ArrayList<SuperVO>();
		for (SuperVO bvo : bodyVOs) {
			List<SuperVO> splitBodyList = new ArrayList<SuperVO>();
			String pk_card = (String) bvo.getAttributeValue(CommonKeyConst.pk_card);
			if (StringUtils.isEmpty(pk_card) || AccbookManager.FLAG_NULL.equals(pk_card)) {
				continue;
			}
			/**
			 * added by wangweiak 2015-03-13
			 * 项目决算生成的项目成本转固单在生成价值调整单时，需要按拆分生成的卡片的原币原值比例分摊“变动部分本币原值”
			 */
			// 因为成本转固单一行表体可以对应多张固定资产卡片，与管理会计达成协定，VO对照过来的每行表体上卡片主键的形式为："AA:BB"
			if (pk_card.contains(":")) {
				String[] pk_cardArr = pk_card.split(":");
				// 按卡片主键排序
				Arrays.sort(pk_cardArr);
				for (int i = 0; i < pk_cardArr.length - 1; i++) {
					SuperVO[] alterBodyVOClones = CloneUtil.deepClone(bvo, pk_cardArr.length - 1);
					if (pk_cardSet.contains(pk_cardArr[i])) {
						alterBodyVOClones[i].setAttributeValue(AssetFieldConst.PK_CARD, pk_cardArr[i]);
						splitBodyList.add(alterBodyVOClones[i]);
					}
				}
				bvo.setAttributeValue(AssetFieldConst.PK_CARD, pk_cardArr[pk_cardArr.length - 1]);
				splitBodyList.add(bvo);
				if (CollectionUtils.isNotEmpty(splitBodyList) && splitBodyList.size() > 1) {
					// 每个表体按照卡片的数量分拆成价值调整单的表体，比如：上游传过来2个表体：第一个表体对应2张卡片，第二个表体对应3张卡片，那价值调整单得是5条表体。
					// 分摊计算的时候，是以2和3为基数计算，两行表体说明CBS不一样，资产类别也不一样
					removeReducedAssetVO(splitBodyList);
					if (CollectionUtils.isEmpty(splitBodyList)) { // 主账簿的卡片全部减少
						continue;
					}
					splitLocaloriginvalueAlter(splitBodyList);
				}
				newBodyList.addAll(splitBodyList);
			} else {
				if (pk_cardSet.contains(pk_card)) {
					newBodyList.add(bvo);
				}
			}
		}
		billVO.setChildrenVO(CollectionUtils.toArray(newBodyList));
	}

	/**
	 * 处理VO对照之后变动VO 1. 传过来的金额，根据币种折算(外部模块传变动单) 2. 添加基本信息(pk_org, pk_org_v,
	 * pk_accbook)
	 * 
	 * @param destVO
	 * @throws BusinessException
	 */
	private void dealWithVOComparisonAfterByOtherModule(AlterVO destVO) throws BusinessException {

		AlterBodyVO[] alterBodyVOs = (AlterBodyVO[]) destVO.getChildrenVO();
		AlterHeadVO alterHeadVO = (AlterHeadVO) destVO.getParentVO();

		/*
		 * 1. 通过卡片主键，查出主账簿的卡片VO
		 */
		List<String> cardsList = VOManager.getAttributeValueList(alterBodyVOs, AlterBodyVO.PK_CARD, true, true);
		if (CollectionUtils.isEmpty(cardsList)) {
			ExceptionUtils.asBusinessException(
					nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0", "02012010-0081"));
		}
		// 查询主账簿卡片数据
		AssetVO[] cardVOs = AMProxy.lookup(IAssetService.class).queryMainAssetVOByPks(null,
				cardsList.toArray(new String[0]));
		AssetVO mainAccbookCardVO = ArrayUtils.isNotEmpty(cardVOs) ? cardVOs[0] : null;
		if (mainAccbookCardVO == null) {
			// 没有此固定资产卡片，请检查.
			ExceptionUtils.asBusinessException(
					nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0", "02012010-0072"));
		}

		// 将卡片转成map类型，key是卡片主键<pk_card, AssetVO>
		Map<String, AssetVO> mainAccbookCardVOsMap = new HashMap<String, AssetVO>();
		for (AssetVO cardVO : cardVOs) {
			mainAccbookCardVOsMap.put(cardVO.getPk_card(), cardVO);
		}

		/*
		 * 2. 设置基本信息，(pk_org, pk_org_v, pk_accbook)
		 */
		// 设置变动单表头特殊信息
		alterHeadVO.setPk_org(mainAccbookCardVO.getPk_org());
		alterHeadVO.setPk_org_v(OrgUtils.getCurVidByPkOrg(mainAccbookCardVO.getPk_org()));
		alterHeadVO.setPk_accbook(mainAccbookCardVO.getPk_accbook());
		alterHeadVO.setBusiness_date(BizContext.getInstance().getBizDate());

		/*
		 * 3. 处理表头，价值折算
		 */
		// 追溯VO
		List<TraceVO> traceVOList = new ArrayList<TraceVO>();

		// 设置表体的折算后的本币原值
		for (AlterBodyVO alterBodyVO : alterBodyVOs) {
			// 当前卡片VO
			AssetVO currentCardVO = mainAccbookCardVOsMap.get(alterBodyVO.getPk_card());
			// 3.1 处理表体
			dealWithConvertBodyVO(alterBodyVO, currentCardVO, alterHeadVO);

			// 3.2 资产追溯调整单
			if (AlterTransiTypeConst.ASSET_TRACE.equals(alterHeadVO.getTransi_type())) {
				// 组装TraceVO
				TraceVO traceVO = assembeTraceVO(currentCardVO, alterBodyVO);
				traceVOList.add(traceVO);
			}
		}

		/*
		 * 4. 资产追溯变动单
		 */
		if (traceVOList.size() != 0) {
			// 处理完追溯信息的VO
			Map<String, TraceResultVO> traceDataVOs = handlerTrace(UFBoolean.FALSE,
					traceVOList.toArray(new TraceVO[0]));
			for (AlterBodyVO bodyVO : alterBodyVOs) {
				String pk_card = bodyVO.getPk_card();
				TraceResultVO resultVO = traceDataVOs.get(pk_card);
				// 将追溯的信息设置到变动表体
				setAlterBodyVOByTraceResult(bodyVO, resultVO);
			}
		}
	}

	/**
	 * 将追溯的信息设置到变动表体
	 * 
	 * @param bodyVO
	 * @param resultVO
	 */
	private void setAlterBodyVOByTraceResult(AlterBodyVO bodyVO, TraceResultVO resultVO) {

		if (resultVO == null) {
			return;
		}
		// 累计折旧
		UFDouble accudepBefore = (UFDouble) bodyVO.getAttributeValue(AlterKeyConst.ACCUDEP_BEFORE);
		// 获取处理后的值
		// 影响前期累计折旧
		UFDouble affectBeforeAccudep = resultVO.getAffectBeforeAccduep();
		// 影响本期累计折旧
		UFDouble affectCurrentAccudep = resultVO.getAffectCurrentAccduep();

		// 变动部分累计折旧
		UFDouble accudepAlter = UFDoubleUtils.add(affectBeforeAccudep, affectCurrentAccudep);

		UFDouble accudepAfter = UFDoubleUtils.add(accudepBefore, accudepAlter);

		// 将处理后的值设置到VO中
		bodyVO.setAttributeValue(AlterKeyConst.DEP_VALUE_BEFORE, affectBeforeAccudep);
		bodyVO.setAttributeValue(AlterKeyConst.DEP_VALUE_CURRENT, affectCurrentAccudep);
		bodyVO.setAttributeValue(AlterKeyConst.ACCUDEP_ALTER, accudepAlter);
		bodyVO.setAttributeValue(AlterKeyConst.ACCUDEP_AFTER, accudepAfter);
		bodyVO.setAttributeValue(AlterBodyVO.TRACEDATE, resultVO.getTraceDate());

	}

	/**
	 * 处理表体VO，先处理折算
	 * 
	 * @param alterBodyVO
	 * @param currentCardVO
	 * @param alterHeadVO
	 * @throws BusinessException
	 */
	private void dealWithConvertBodyVO(AlterBodyVO alterBodyVO, AssetVO currentCardVO, AlterHeadVO alterHeadVO)
			throws BusinessException {

		// 设置财务组织
		alterBodyVO.setPk_org(alterHeadVO.getPk_org());
		alterBodyVO.setPk_org_v(alterHeadVO.getPk_org_v());
		alterBodyVO.setPk_accbook(currentCardVO.getPk_accbook());
		alterBodyVO.setPk_currency(currentCardVO.getPk_currency());

		// 变动部分本币原值
		UFDouble localoriginvalueAlter = (UFDouble) alterBodyVO.getAttributeValue(AlterKeyConst.LOCALORIGINVALUE_ALTER);

		// 外部模块的币种
		String pk_src_currtype = (String) alterBodyVO.getAttributeValue(AlterKeyConst.PK_SRC_CURRENCY);

		if (StringUtils.isEmpty(pk_src_currtype)) {
			ExceptionUtils.asBusinessException(
					nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0", "02012010-0079")
			/*
			 * @res "来源传过来的币种为空, 请检查. "
			 */);
		}

		// 取账簿信息的表头
		AccbookHeadVO accbookHeadVO = AMProxy.lookup(IAccbookInfoService.class)
				.queryAccbookHeadVOByAccbook(currentCardVO.getPk_accbook());
		// 外币折算日期 0 -- 卡片建卡日期 1 -- 业务发生日期
		int convertInt = accbookHeadVO.getConvert_date();
		// 折算日期
		UFDate convertDate = null;
		// 卡片建卡日期
		if (ConvertData.CARD_CREATE_DATA.value().equals(convertInt)) {
			convertDate = currentCardVO.getBusiness_date();
		} else {
			convertDate = alterHeadVO.getBusiness_date();
		}
		// 经过币种折算后，变动部分本币原值
		localoriginvalueAlter = CurrencyRateManager.getAccbookAmountByOpp(currentCardVO.getPk_accbook(),
				pk_src_currtype, localoriginvalueAlter, convertDate);

		// 本币原值
		UFDouble localoriginvalueBefore = currentCardVO.getLocaloriginvalue();
		alterBodyVO.setAttributeValue(AlterKeyConst.LOCALORIGINVALUE_ALTER, localoriginvalueAlter);
		alterBodyVO.setAttributeValue(AlterKeyConst.LOCALORIGINVALUE_BEFORE, localoriginvalueBefore);
		UFDouble localoriginvalueAfter = UFDoubleUtils.add(localoriginvalueAlter, localoriginvalueBefore);
		alterBodyVO.setAttributeValue(AlterKeyConst.LOCALORIGINVALUE_AFTER, localoriginvalueAfter);

		if (UFDoubleUtils.isNullOrZero(localoriginvalueAfter)
				|| localoriginvalueAfter.compareTo(UFDouble.ZERO_DBL) < 0) {
			ExceptionUtils.asBusinessException(
					nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("alter_0", "02012010-0078")
			/*
			 * @res "来源传过来的金额导致固定资产的本币原值小于0, 请检查  \n "
			 */);
		}

		// 净残值
		alterBodyVO.setAttributeValue(AlterKeyConst.SALVAGE_BEFORE, currentCardVO.getSalvage());
		UFDouble after_salvage = UFDoubleUtils
				.multiply((UFDouble) alterBodyVO.getAttributeValue(AlterKeyConst.LOCALORIGINVALUE_AFTER),
						currentCardVO.getSalvagerate())
				.div(100);
		alterBodyVO.setAttributeValue(AlterKeyConst.SALVAGE_AFTER, after_salvage);
		alterBodyVO.setAttributeValue(AlterKeyConst.SALVAGE_ALTER,
				UFDoubleUtils.sub(after_salvage, currentCardVO.getSalvage()));

		// 净残值率
		alterBodyVO.setAttributeValue(AlterKeyConst.SALVAGERATE_BEFORE, currentCardVO.getSalvagerate());
		alterBodyVO.setAttributeValue(AlterKeyConst.SALVAGERATE_AFTER, currentCardVO.getSalvagerate());

		// 累计折旧(资产追溯)
		if (AlterTransiTypeConst.ASSET_TRACE.equals(alterHeadVO.getTransi_type())) {
			alterBodyVO.setAttributeValue(AlterKeyConst.ACCUDEP_BEFORE, currentCardVO.getAccudep());
		}

		// 使用月限
		alterBodyVO.setAttributeValue(AlterKeyConst.SERVICEMONTH_BEFORE, currentCardVO.getServicemonth());
		alterBodyVO.setAttributeValue(AlterKeyConst.SERVICEMONTH_AFTER, currentCardVO.getServicemonth());
		alterBodyVO.setAttributeValue(AlterKeyConst.NATUREMONTH_BEFORE, currentCardVO.getNaturemonth());
		alterBodyVO.setAttributeValue(AlterKeyConst.NATUREMONTH_AFTER, currentCardVO.getNaturemonth());
	}

	/**
	 * 组装追溯VO
	 * 
	 * @param currentCardVO
	 * @param alterBodyVO
	 * @return
	 */
	private TraceVO assembeTraceVO(AssetVO currentCardVO, AlterBodyVO alterBodyVO) {

		// 本币原值
		UFDouble localOriginValueAfter = (UFDouble) alterBodyVO.getAttributeValue(AlterKeyConst.LOCALORIGINVALUE_AFTER);
		// 可使用月限
		Integer useMonthAfter = currentCardVO.getServicemonth();
		// 净残值率
		UFDouble salvageRateAfter = currentCardVO.getSalvagerate();

		// 追溯日期：默认卡片的“折旧开始日期”。
		UFDate traceDate = currentCardVO.getDep_start_date();

		// 卡片pk
		String pk_card = currentCardVO.getPk_card();

		// 当前的所在的财务账簿
		String pk_accbook = currentCardVO.getPk_accbook();

		String pk_org = currentCardVO.getPk_org();

		String pk_depmethod = currentCardVO.getPk_accbook();

		String card_code = currentCardVO.getCard_code();

		TraceVO traceVO = new TraceVO();
		traceVO.setPk_org(pk_org);
		traceVO.setPk_card(pk_card);
		traceVO.setPk_accbook(pk_accbook);
		traceVO.setTraceDate(traceDate);
		traceVO.setLocalOriginValueAfter(localOriginValueAfter);
		traceVO.setUseMonthAfter(useMonthAfter);
		traceVO.setSalvageRateAfter(salvageRateAfter);
		traceVO.setPk_depmethod(pk_depmethod);
		traceVO.setCard_code(card_code);

		traceVO.setSalvageAfter(
				new UFDouble(localOriginValueAfter.doubleValue() * salvageRateAfter.doubleValue() / 100));
		return traceVO;
	}

	/**
	 * 根据管控模式，查询变动方式编码和名称（用于V631审计接口查询数据）
	 * 
	 * @param pk_org
	 * @return
	 * @throws BusinessException add by wangweiak
	 */
	@SuppressWarnings({ "unchecked", "serial" })
	public List<AlterBodyVO> queryAlterStyleData(String pk_org) throws BusinessException {
		// 获取集团
		String pk_group = InvocationInfoProxy.getInstance().getGroupId();

		// 一、查询“增减方式-集团”中的所有数据；
		// 1、组装查询sql（管控模式为集团、全局）
		// String querySQL = "select style_code, style_name from pam_addreducestyle
		// where ( pk_org = '"
		// + pk_group + "' or pk_org = '" + IOrgConst.GLOBEORG + "') ";
		StringBuffer querySql = new StringBuffer();
		querySql.append(" select style_code ").append("       ,style_name ").append("   from pam_addreducestyle ")
				.append("  where pk_org = '" + pk_group + "' ").append("     or pk_org = '" + IOrgConst.GLOBEORG + "' ")
				.append("  order by style_code ");

		DBAccessUtil dbUtil = new DBAccessUtil();
		final List<AlterBodyVO> alterBodyVOList = (List<AlterBodyVO>) dbUtil.getBaseDAO()
				.executeQuery(querySql.toString(), new ResultSetProcessor() {

					@Override
					public Object handleResultSet(ResultSet rs) throws SQLException {

						List<AlterBodyVO> alterBodyVOList = new ArrayList<AlterBodyVO>();
						while (rs.next()) {
							String style_code = rs.getString(AddreduceStyleVO.STYLE_CODE);
							String style_name = rs.getString(AddreduceStyleVO.STYLE_NAME);
							AlterBodyVO alterBodyVO = new AlterBodyVO();
							alterBodyVO.setDef1(style_code); // 用自定义项1来临时存储变动方式编码
							alterBodyVO.setDef2(style_name); // 用自定义项2来临时存储变动方式名称
							alterBodyVOList.add(alterBodyVO);
						}
						return alterBodyVOList;
					}
				});

		// 二、查询集团下“资产变动”单据类型下配置的所有交易类型编码和交易类型名称
		// 1、组装查询sql（查bd_billtype表）
		// String queryAlterSQL = " select pk_billtypecode, billtypename from
		// bd_billtype where parentbilltype = 'HG' " +
		// " and pk_group = '" + pk_group + "'";
		StringBuffer queryAlterSql = new StringBuffer();
		queryAlterSql.append(" select pk_billtypecode ").append("       ,billtypename ").append("   from bd_billtype ")
				.append("  where parentbilltype = 'HG' ").append("    and pk_group = '" + pk_group + "' ")
				.append("  order by pk_billtypecode ");
		dbUtil.getBaseDAO().executeQuery(queryAlterSql.toString(), new ResultSetProcessor() {

			@Override
			public Object handleResultSet(ResultSet rs) throws SQLException {
				while (rs.next()) {
					String billtypeCode = rs.getString("pk_billtypecode"); // 获取“资产变动”下的交易类型编码，格式为：HG-01
					String new_billtypeCode = "03" + billtypeCode.substring(3); // 将格式调整为：0301
					String billypeName = rs.getString("billtypename"); // 获取“资产变动”下的交易类型名称
					AlterBodyVO alterBodyVO = new AlterBodyVO();
					alterBodyVO.setDef1(new_billtypeCode); // 用自定义项1来临时存储交易类型编码
					alterBodyVO.setDef2(billypeName); // 用自定义项2来临时存储交易类型名称
					if (CollectionUtils.isNotEmpty(alterBodyVOList)) {
						alterBodyVOList.add(alterBodyVO);
					}
				}
				return alterBodyVOList;
			}
		});

		return alterBodyVOList;
	}

	/**
	 * 根据表体中各卡片原币原值所占的比例来分摊“变动部分本币原值”。
	 * 
	 * @param splitBodyList 需要进行比例折算的变动单表体
	 * @throws BusinessException
	 */
	public void splitLocaloriginvalueAlter(List<SuperVO> splitBodyList) throws BusinessException {
		List<String> cardsList = VOManager.getAttributeValueList(splitBodyList.toArray(new AlterBodyVO[0]),
				AlterBodyVO.PK_CARD, true, true);
		// 查询主账簿卡片数据
		AssetVO[] assetVOs = AMProxy.lookup(IAssetService.class).queryMainAssetVOByPks(null,
				cardsList.toArray(new String[0]));
		// 变动部分本币原值（需要将该值按照pk_cardArr[]中各个卡片所占的原币原值比例进行分摊）
		UFDouble localoriginvalueAlter = (UFDouble) splitBodyList.get(0)
				.getAttributeValue(AlterKeyConst.LOCALORIGINVALUE_ALTER);
		UFDouble originvalueSum = UFDouble.ZERO_DBL;
		UFDouble localoriginvalueUsed = UFDouble.ZERO_DBL;
		for (AssetVO assetVO : assetVOs) {
			originvalueSum = originvalueSum.add(assetVO.getOriginvalue());
		}
		// 取变动单表体账簿的精度
		String pk_accbook = assetVOs[0].getPk_accbook();
		for (AssetVO assetVO : assetVOs) {
			for (int i = 0; i < splitBodyList.size() - 1; i++) {
				AlterBodyVO bodyVO = (AlterBodyVO) splitBodyList.get(i);
				if (assetVO.getPk_card().equals(bodyVO.getPk_card())) {
					UFDouble originvalue = assetVO.getOriginvalue(); // 原币原值
					UFDouble localoriginvalue_acc = FAScaleUtils.setScaleByAccbook(
							localoriginvalueAlter.multiply(originvalue).div(originvalueSum), pk_accbook);
					bodyVO.setAttributeValue(AlterKeyConst.LOCALORIGINVALUE_ALTER, localoriginvalue_acc);
					localoriginvalueUsed = FAScaleUtils
							.setScaleByAccbook(localoriginvalueUsed.add(localoriginvalue_acc), pk_accbook);
				}
			}
		}
		// 最后一行表体用倒减的方式
		splitBodyList.get(splitBodyList.size() - 1).setAttributeValue(AlterKeyConst.LOCALORIGINVALUE_ALTER,
				localoriginvalueAlter.sub(localoriginvalueUsed));
	}

	/**
	 * 过滤掉主账簿减少的卡片。
	 * 
	 * @param splitBodyList
	 * @throws BusinessException
	 */
	private void removeReducedAssetVO(List<SuperVO> splitBodyList) throws BusinessException {
		// 取得表体所有资产卡片是否减少的判断结果。
		String[] pk_cards = VOManager.getAttributeValueArray(splitBodyList.toArray(new SuperVO[0]),
				AssetFieldConst.PK_CARD);
		Map<String, Boolean> reducedAsset = AMProxy.lookup(IReduceService.class).isCardMainAccbookReduced(pk_cards);
		List<AlterBodyVO> countList = new ArrayList<AlterBodyVO>();

		// 取得含有未减少卡片的表体。
		for (SuperVO bodyVO : splitBodyList) {
			AlterBodyVO alterBodyVO = (AlterBodyVO) bodyVO;
			if (reducedAsset.get(alterBodyVO.getPk_card())) {
				countList.add(alterBodyVO);
			}
		}
		if (CollectionUtils.isNotEmpty(countList)) {
			splitBodyList.removeAll(countList);
		}
	}

	/**
	 * 变动单卡片编辑后事件使用, 来远程拉数据 为减少连接次数使用
	 * 
	 * @author tanghui5
	 */
	@Override
	public Map<String, Object> fetchAlterCardEditData(String pk_org, String pk_accbook, String[] queryFields,
			String[] pk_cards) throws BusinessException {
		Map<String, Object> alterCardEditData = new HashMap<String, Object>();

		// 查询卡片数据
		AssetVO[] assetVOs = null;
		String[] tqueryFields = ArrayUtils.addElement(queryFields, new String[] { "accyear", "period" });
		assetVOs = AMProxy.lookup(IAssetService.class).queryAssetVOByAlter(pk_org, pk_accbook, tqueryFields, pk_cards);
		alterCardEditData.put("assetVOs", assetVOs);

		// 查询多使用部门
		Map<String, List<DeptScaleVO>> deptMap = new HashMap<String, List<DeptScaleVO>>();
		deptMap = AMProxy.lookup(IAssetService.class).queryUseDeptBatch(pk_cards);
		alterCardEditData.put("deptMap", deptMap);

		// 过滤含有已停用部门的多使用部门数据
		Map<String, List<DeptScaleVO>> filteredDeptMap = new HashMap<String, List<DeptScaleVO>>();
		filteredDeptMap = AMProxy.lookup(IUseDeptScaleService.class).filterDeptSeal(deptMap, pk_org);
		alterCardEditData.put("filteredDeptMap", filteredDeptMap);

		return alterCardEditData;
	}

}/// :~
