package nccloud.itf.sscivm.ivsale.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import nc.bs.businessevent.EventDispatcher;
import nc.bs.dao.BaseDAO;
import nc.bs.framework.common.InvocationInfoProxy;
import nc.bs.framework.common.NCLocator;
import nc.bs.framework.common.RuntimeEnv;
import nc.bs.pub.pf.PfUtilTools;
import nc.bs.sscivm.ivsale.bp.IVApplicationDeleteBP;
import nc.bs.sscivm.ivsale.bp.IVApplicationInsertBP;
import nc.bs.sscivm.ivsale.bp.IVApplicationQueryBP;
import nc.bs.sscivm.ivsale.bp.IVApplicationUpdateBP;
import nc.bs.sscivm.ivsale.ivaconst.IVAWebConst;
import nc.bs.sscivm.ivsale.splitmerge.util.TransSpiltMergePksUtil;
import nc.bs.sscivm.ivsale.util.ActionUtils;
import nc.bs.sscivm.ivsale.util.ApplicationBusinessEvent;
import nc.bs.sscivm.ivsale.util.IVApplicationBillDefValue;
import nc.bs.sscivm.ivsale.util.IVApplicationEventType;
import nc.bs.sscivm.ivsale.util.IVApplicationSlsmUtil;
import nc.bs.sscivm.ivsale.util.IVSaleUtil;
import nc.bs.sscivm.logger.SSCIVMLogger;
import nc.bs.sscivm.util.IVMSagaValidationUtils;
import nc.impl.pubapp.pattern.data.bill.tool.BillTransferTool;
import nc.itf.bd.material.baseinfo.IMaterialBaseInfoQueryService;
import nc.itf.uap.pf.IWorkflowDefine;
import nc.itf.uap.pf.IWorkflowMachine;
import nc.itf.uap.pf.metadata.IFlowBizItf;
import nc.jdbc.framework.processor.ColumnProcessor;
import nc.pubitf.bbd.CurrtypeQuery;
import nc.pubitf.para.SysInitQuery;
import nc.pubitf.uapbd.CurrencyRateUtilHelper;
import nc.pubitf.uapbd.ICustomerPubService;
import nc.pubitf.uapbd.IMaterialPubService;
import nc.uap.pf.metadata.PfMetadataTools;
import nc.vo.bd.currtype.CurrtypeVO;
import nc.vo.bd.material.MaterialVO;
import nc.vo.bd.material.MaterialVersionVO;
import nc.vo.ic.pub.util.StringUtil;
import nc.vo.ml.NCLangRes4VoTransl;
import nc.vo.org.OrgQueryUtil;
import nc.vo.org.OrgVO;
import nc.vo.pf.change.PfUtilBaseTools;
import nc.vo.pf.pub.util.SQLUtil;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.BusinessException;
import nc.vo.pub.CircularlyAccessibleValueObject;
import nc.vo.pub.VOStatus;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDate;
import nc.vo.pub.lang.UFDateTime;
import nc.vo.pub.lang.UFDouble;
import nc.vo.pub.pf.workflow.IPFActionName;
import nc.vo.pub.workflownote.WorkflownoteVO;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nc.vo.sscivm.ivmpub.IVAplocationFPXZ;
import nc.vo.sscivm.ivmpub.IVAplocationKPFS;
import nc.vo.sscivm.ivsale.IVApplicationAggVO;
import nc.vo.sscivm.ivsale.IVApplicationBodyVO;
import nc.vo.sscivm.ivsale.IVApplicationHeadVO;
import nc.vo.sscivm.ivsale.IVApplogVO;
import nc.vo.sscivm.ivsale.IVBilltypeVO;
import nc.vo.sscivm.ivsale.IVTspzsBodyVO;
import nc.vo.sscivm.ivsale.MessageVO;
import nc.vo.trade.pub.IBillStatus;
import nc.vo.uap.pf.PFBusinessException;
import nc.vo.uap.pf.PfProcessBatchRetObject;
import nc.vo.wfengine.definition.WorkflowTypeEnum;
import nccloud.commons.lang.StringUtils;
import nccloud.itf.sscivm.ivsale.service.ApplicationLogService;
import nccloud.itf.sscivm.ivsale.service.IVABilltypeExtService;
import nccloud.itf.sscivm.ivsale.service.IVApplicationInvoiceService;
import nccloud.itf.sscivm.ivsale.service.IVApplicationQueryService;
import nccloud.itf.sscivm.ivsale.service.IVApplicationService;
import nccloud.pubitf.riart.pflow.CloudPFlowContext;
import nccloud.pubitf.riart.pflow.ICloudScriptPFlowService;
import nccloud.putitf.riart.billtype.IBilltypeService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class IVApplicationServiceImpl implements IVApplicationService {

    @Override
    public IVApplicationAggVO save(IVApplicationAggVO ivApplicationVO) throws BusinessException {
        IVApplicationAggVO[] ivApplicationVOs = null;
        try {
            ivApplicationVOs = saveBatch(new IVApplicationAggVO[] { ivApplicationVO });
        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }
        return ivApplicationVOs == null || ivApplicationVOs.length == 0 ? null : ivApplicationVOs[0];

    }

    @Override
    public IVApplicationAggVO[] saveBatch(IVApplicationAggVO[] clientFullVOs) throws BusinessException {
        IVApplicationAggVO[] retvos = null;
        HashSet<IVApplicationAggVO> retVOLits = new HashSet<IVApplicationAggVO>();
        try {
            //BillTransferTool<IVApplicationAggVO> transferTool = new BillTransferTool<IVApplicationAggVO>(clientFullVOs);
            IVApplicationInsertBP action = new IVApplicationInsertBP();
            retvos = action.insert(clientFullVOs);
            //retvos = (IVApplicationAggVO[]) transferTool.getBillForToClient(retvos);
            //处理自动提交
            HashSet<String> tradetypeids = new HashSet<String>();
            for (IVApplicationAggVO applicationAggVO : retvos) {
                tradetypeids.add(applicationAggVO.getParentVO().getTranstypecode());
            }
            IVBilltypeVO[] billtypeVOS =
                    NCLocator
                            .getInstance()
                            .lookup(IVABilltypeExtService.class)
                            .getBilltypeVOsByWhere(
                                    " "
                                            + IVBilltypeVO.PK_GROUP
                                            + " ='"
                                            + InvocationInfoProxy.getInstance().getGroupId()
                                            + "' and "
                                            + SQLUtil.buildSqlForIn(IVBilltypeVO.BILLTYPECODE,
                                            tradetypeids.toArray(new String[tradetypeids.size()])));
            //提交时处理自动审批功能
            if (billtypeVOS != null && billtypeVOS.length > 0) {
                // 3、自动提交勾选时
                HashSet<IVApplicationAggVO> atuoVOs = new HashSet<IVApplicationAggVO>();
                HashSet<IVApplicationAggVO> noatuoVOs = new HashSet<IVApplicationAggVO>();
                for (IVApplicationAggVO retvo : retvos) {
                    boolean Isatuo_submit = UFBoolean.FALSE.booleanValue();
                    for (IVBilltypeVO billtypeVO : billtypeVOS) {
                        if (retvo.getParentVO().getTranstypecode() != null
                                && retvo.getParentVO().getTranstypecode()
                                .equals(billtypeVO.getBilltypecode())) {
                            if (billtypeVO.getIsatuo_submit() == UFBoolean.TRUE) {
                                Isatuo_submit = UFBoolean.TRUE.booleanValue();
                            }
                        }
                    }

                    if (Isatuo_submit) {
                        atuoVOs.add(retvo);
                    } else {
                        noatuoVOs.add(retvo);
                    }
                }

                if (atuoVOs != null && atuoVOs.size() > 0) {
                    Object submitObj = this.submit(atuoVOs.toArray(new IVApplicationAggVO[atuoVOs.size()]), null, null);
                    if (submitObj instanceof Map) {
                        throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0053")/*@res "开票申请单保存提交失败，下游环节含有指派信息"*/);
                    }

                    retvos = (IVApplicationAggVO[])submitObj;
                    if (retvos != null && retvos.length > 0) {
                        for(IVApplicationAggVO retvo : retvos) {
                            retVOLits.add(retvo);
                        }

                        if (noatuoVOs != null && noatuoVOs.size() > 0) {
                            retVOLits.addAll(noatuoVOs);
                        }
                    }
                    retvos = retVOLits.toArray(new IVApplicationAggVO[retVOLits
                            .size()]);
                } else {
                    if (noatuoVOs != null && noatuoVOs.size() > 0) {
                        retVOLits.addAll(noatuoVOs);
                        retvos = retVOLits
                                .toArray(new IVApplicationAggVO[retVOLits
                                        .size()]);
                    }
                }
            }
        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }

        return retvos;
    }

    @Override
    public void deleteById(String pk) throws BusinessException {
        deleteByIds(new String[] { pk });
    }

    @Override
    public void deleteByIds(String[] pks) throws BusinessException {
        IVApplicationAggVO[] retvos = new IVApplicationQueryBP().queryAggIVApplicationVOByCondition(SQLUtil.buildSqlForIn(
                IVApplicationHeadVO.PK_IVAPPLICATION, pks));
        new IVApplicationDeleteBP().delete(retvos);
    }

    @Override
    public void delete(IVApplicationAggVO vo) throws BusinessException {
        try {
            new IVApplicationDeleteBP().delete(new IVApplicationAggVO[] { vo });
        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }
    }

    @Override
    public void deleteBatch(IVApplicationAggVO[] vos) throws BusinessException {
        try {
            new IVApplicationDeleteBP().delete(vos);
        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }
    }
    @Override
    public void deleteBatchdUnCheckApproveStaus(IVApplicationAggVO[] vos) throws BusinessException {
        try {
            new IVApplicationDeleteBP().deleteUnCheckApproveStaus(vos);
        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }
    }
    @Override
    public IVApplicationAggVO update(IVApplicationAggVO ivApplicationVO) throws BusinessException {
        IVApplicationAggVO[] retvos = null;
        try {
            if (ivApplicationVO == null
                    || ivApplicationVO.getParentVO() == null) {
                return null;
            }

            Integer approveStatus = ivApplicationVO.getParentVO()
                    .getBillstatus();
            // 审批通过的单据不允许修改
            if (approveStatus.intValue() == IBillStatus.CHECKPASS) {
                throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl
                        .getNCLangRes()
                        .getStrByID("1058sal_0", "01058sal-0024")/*
                 * @res
                 * "审批通过的单据不允许修改"
                 */);
            }
            // 审批进行中的单据只允许当前审批人修改
            if (approveStatus.intValue() == IBillStatus.COMMIT
                    || approveStatus.intValue() == IBillStatus.CHECKGOING) {
                String billId = ivApplicationVO.getParentVO()
                        .getPk_ivapplication();
                String billType = ivApplicationVO.getParentVO()
                        .getTranstypecode();
                String userId = InvocationInfoProxy.getInstance().getUserId();
                if (!isFlowCheckman(billId, billType, userId)) {
                    throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl
                            .getNCLangRes().getStrByID("1058sal_0",
                                    "01058sal-0050")/*
                     * @res
                     * "审批流程中的单据，只有当前审批人可以修改!"
                     */);
                }
            }

            retvos = updateBatch(new IVApplicationAggVO[] { ivApplicationVO }, null);
            if(retvos!=null && retvos.length>0){
                CircularlyAccessibleValueObject[] bodys = retvos[0].getChildrenVO();
                if(bodys!=null && bodys.length>0){
                    for(int m=0;m<bodys.length;m++){
                        CircularlyAccessibleValueObject body = bodys[m];
                        body.setAttributeValue("rowid", ivApplicationVO.getChildrenVO()[m].getAttributeValue("rowid"));
                    }
                }
            }
        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }
        return retvos == null || retvos.length == 0 ? null : retvos[0];
    }

    @Override
    public IVApplicationAggVO[] updateBatch(IVApplicationAggVO[] clientFullVOs, IVApplicationAggVO[] originBills) throws BusinessException {
        IVApplicationAggVO[] retvos = null;
        try {
            BillTransferTool<IVApplicationAggVO> transferTool = new BillTransferTool<IVApplicationAggVO>(clientFullVOs);
            IVApplicationUpdateBP action = new IVApplicationUpdateBP();
            originBills = transferTool.getOriginBills();
            retvos = action.update(clientFullVOs, originBills);

        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }
        return retvos;
    }

    /**
     * 开票申请更新，由卡片界面修改保存触发，与开票状态更新、协同更新、开票金额等区分开
     * @param ivApplicationVO
     * @return
     * @throws BusinessException
     */
    @Override
    public IVApplicationAggVO updateForUI(IVApplicationAggVO ivApplicationVO) throws BusinessException {
        IVApplicationAggVO[] retvos = null;
        try {
            if (ivApplicationVO == null
                    || ivApplicationVO.getParentVO() == null) {
                return null;
            }

            Integer approveStatus = ivApplicationVO.getParentVO()
                    .getBillstatus();
            // 审批通过的单据不允许修改
            if (approveStatus.intValue() == IBillStatus.CHECKPASS) {
                throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl
                        .getNCLangRes()
                        .getStrByID("1058sal_0", "01058sal-0024")/*
                 * @res
                 * "审批通过的单据不允许修改"
                 */);
            }
            // 审批进行中的单据只允许当前审批人修改
            if (approveStatus.intValue() == IBillStatus.COMMIT
                    || approveStatus.intValue() == IBillStatus.CHECKGOING) {
                String billId = ivApplicationVO.getParentVO()
                        .getPk_ivapplication();
                String billType = ivApplicationVO.getParentVO()
                        .getTranstypecode();
                String userId = InvocationInfoProxy.getInstance().getUserId();
                if (!isFlowCheckman(billId, billType, userId)) {
                    throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl
                            .getNCLangRes().getStrByID("1058sal_0",
                                    "01058sal-0050")/*
                     * @res
                     * "审批流程中的单据，只有当前审批人可以修改!"
                     */);
                }
            }
            //如果来源单据为销售发票,根据来源单据编号src_billno和来源单据类型（billtype = 32）查询销售发票价税合计（ntotalorigmny）与开票申请中价税合计（jshj）比较，须满足 jshj<ntotalorigmny
            String src_billtype = ivApplicationVO.getParentVO().getSrc_billtype(); //来源单据类型
            String src_billno = ivApplicationVO.getParentVO().getSrc_billno(); //来源单据号
            String def23 = ivApplicationVO.getParentVO().getDef23(); //bip开票类型 （3：出口发票）
            //根据开票申请自定义项23查询自定义档案编码
            BaseDAO dao = new BaseDAO();
            String sqlDefdoc = "select code from bd_defdoc where dr = 0 and pk_defdoc = '" +def23+"'";
            Object objDefdoc = dao.executeQuery(sqlDefdoc, new ColumnProcessor());
            String def23Code = "";
            if(objDefdoc != null) {
                def23Code = objDefdoc.toString();
            }
            /**
             * 2025-03-12新增：
             *  开票申请自定义项 23（bip开票类型） 不等于 3，def23Code ！= 3
             *  再做金额校验
             */
            if("32".equals(src_billtype) && !StringUtil.isNullStringOrNull(src_billno) && !"3".equals(def23Code)){
                String sql = "select ntotalorigmny from so_saleinvoice where dr = 0 and vbillcode = '" +src_billno+"'";
                Object obj = dao.executeQuery(sql, new ColumnProcessor());
                //销售发票价税合计
                UFDouble ntotalorigmny = UFDouble.ZERO_DBL;
                if(obj != null) {
                    ntotalorigmny = new UFDouble(obj.toString());
                }
                //开票申请价税合计
                UFDouble jshj = ivApplicationVO.getParentVO().getJshj();
                //如果开票申请价税合计 大于 销售发票价税合计则返回报错
                if(jshj != null && ntotalorigmny != null && jshj.compareTo(ntotalorigmny) != 0){
                    throw new BusinessException("价税合计必须和销售发票中价税合计一致");
                }
            }


            retvos = updateBatchForUI(new IVApplicationAggVO[] { ivApplicationVO }, null);
            if(retvos!=null && retvos.length>0){
                CircularlyAccessibleValueObject[] bodys = retvos[0].getChildrenVO();
                if(bodys!=null && bodys.length>0){
                    for(int m=0;m<bodys.length;m++){
                        CircularlyAccessibleValueObject body = bodys[m];
                        body.setAttributeValue("rowid", ivApplicationVO.getChildrenVO()[m].getAttributeValue("rowid"));
                    }
                }
            }
        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }
        return retvos == null || retvos.length == 0 ? null : retvos[0];
    }

    private IVApplicationAggVO[] updateBatchForUI(IVApplicationAggVO[] clientFullVOs, IVApplicationAggVO[] originBills) throws BusinessException {
        IVApplicationAggVO[] retvos = null;
        try {
            BillTransferTool<IVApplicationAggVO> transferTool = new BillTransferTool<IVApplicationAggVO>(clientFullVOs);
            IVApplicationUpdateBP action = new IVApplicationUpdateBP();
            originBills = transferTool.getOriginBills();
            retvos = action.update(clientFullVOs, originBills);

            // 处理自动提交，前提：自由态修改保存到自由态
            Map<String, IVApplicationAggVO> pkAndOldVOMap = new HashMap<>();
            for(IVApplicationAggVO aggVO : originBills){
                pkAndOldVOMap.put(aggVO.getPrimaryKey(), aggVO);
            }
            HashSet<String> tradetypeids = new HashSet<String>();
            for (IVApplicationAggVO applicationAggVO : retvos) {
                IVApplicationAggVO oldApplicationAggVO = pkAndOldVOMap.get(applicationAggVO.getPrimaryKey());
                if(applicationAggVO.getParentVO().getBillstatus() == IBillStatus.FREE && oldApplicationAggVO.getParentVO().getBillstatus() == IBillStatus.FREE){
                    tradetypeids.add(applicationAggVO.getParentVO().getTranstypecode());
                }
            }
            if(tradetypeids.size() == 0){
                return retvos;
            }
            IVBilltypeVO[] billtypeVOS = NCLocator.getInstance().lookup(IVABilltypeExtService.class).getBilltypeVOsByWhere(" "
                    + IVBilltypeVO.PK_GROUP
                    + " ='"
                    + InvocationInfoProxy.getInstance().getGroupId()
                    + "' and "
                    + SQLUtil.buildSqlForIn(IVBilltypeVO.BILLTYPECODE,
                    tradetypeids.toArray(new String[tradetypeids.size()])));
            if (billtypeVOS != null && billtypeVOS.length > 0) {
                // 交易类型自动提交勾选时
                HashSet<IVApplicationAggVO> atuoVOs = new HashSet<IVApplicationAggVO>();
                HashSet<IVApplicationAggVO> noatuoVOs = new HashSet<IVApplicationAggVO>();
                for (IVApplicationAggVO retvo : retvos) {
                    boolean Isatuo_submit = UFBoolean.FALSE.booleanValue();
                    for (IVBilltypeVO billtypeVO : billtypeVOS) {
                        if (retvo.getParentVO().getTranstypecode() != null
                                && retvo.getParentVO().getTranstypecode().equals(billtypeVO.getBilltypecode())){
                            if (billtypeVO.getIsatuo_submit() == UFBoolean.TRUE) {
                                Isatuo_submit = UFBoolean.TRUE.booleanValue();
                            }
                        }
                    }
                    if (Isatuo_submit) {
                        atuoVOs.add(retvo);
                    } else {
                        noatuoVOs.add(retvo);
                    }
                }
                List<IVApplicationAggVO> retVOLits = new ArrayList<>();
                if (atuoVOs != null && atuoVOs.size() > 0) {
                    Object submitObj = this.submit(atuoVOs.toArray(new IVApplicationAggVO[atuoVOs.size()]), null, null);
                    if (submitObj instanceof Map) {
                        throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0",
                                "01058sal-0053")/* @res "开票申请单保存提交失败，下游环节含有指派信息" */);
                    }
                    retvos = (IVApplicationAggVO[]) submitObj;
                    if (retvos != null && retvos.length > 0) {
                        for (IVApplicationAggVO retvo : retvos) {
                            retVOLits.add(retvo);
                        }
                        if (noatuoVOs != null && noatuoVOs.size() > 0) {
                            retVOLits.addAll(noatuoVOs);
                        }
                    }
                    retvos = retVOLits.toArray(new IVApplicationAggVO[retVOLits.size()]);
                } else {
                    if (noatuoVOs != null && noatuoVOs.size() > 0) {
                        retVOLits.addAll(noatuoVOs);
                        retvos = retVOLits.toArray(new IVApplicationAggVO[retVOLits.size()]);
                    }
                }
            }
        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }
        return retvos;
    }

    @Override
    public Object submit(IVApplicationAggVO[] clientBills, IVApplicationAggVO[] originBills, Object assingUsers) throws BusinessException {
        //判断saga状态
        if(clientBills != null && clientBills.length > 0) {
            String[] pks = new String[clientBills.length];
            for (int i = 0; i < clientBills.length; i++) {
                pks[i] = clientBills[i].getParentVO().getPk_ivapplication();
            }

            IVMSagaValidationUtils.checkSagaStatus(pks, IVApplicationHeadVO.getDefaultTableName(), IVApplicationHeadVO.PK_IVAPPLICATION);
        }
        List<IVApplicationAggVO> retvos = new ArrayList<IVApplicationAggVO>();
        try {

            for (int i = 0; i < clientBills.length; i++) {
                AggregatedValueObject billVO = clientBills[i];
                if (clientBills[i].getParentVO().getBillstatus() != IBillStatus.FREE) {
                    // 存在非自由态的单据
                    throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0025")/*@res "第:"*/ + (i + 1) + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0026")/*@res "行，非自由态的单据不允许提交!"*/);
                }
                Object retObj = doNccCommit(billVO, assingUsers);
                if(retObj instanceof Map){
                    return retObj;
                }
                if (retObj != null) {
                    retvos.add((IVApplicationAggVO)((MessageVO)retObj).getSuccessVO());
                }
            }
        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }
        return retvos.toArray(new IVApplicationAggVO[retvos.size()]);
    }

    private Object doNccCommit(AggregatedValueObject aggVos, Object assingUsers) throws Exception {
        MessageVO result = null;

        IVApplicationQueryService ivApplicationQueryService =
                NCLocator.getInstance().lookup(IVApplicationQueryService.class);

        AggregatedValueObject billVO = aggVos;
        String djlxbm = null;
        try {
            if (billVO.getParentVO() instanceof IVApplicationHeadVO) {
                IVApplicationAggVO[] submitVos =
                        ivApplicationQueryService
                                .queryAggVOsByPks(new String[] {((IVApplicationHeadVO)billVO.getParentVO()).getPrimaryKey()});
                if (submitVos != null && submitVos.length > 0) {
                    if (null == ((IVApplicationHeadVO)billVO.getParentVO()).getTs()
                            || ((IVApplicationHeadVO)billVO.getParentVO()).getTs().compareTo(
                            submitVos[0].getParentVO().getTs()) != 0) {
                        throw new Exception(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0", "01058sal-0057")/*@res "单据已经被他人修改,请刷新页面!"*/);
                    }
                }

                String tradetypePk = ((IVApplicationHeadVO)billVO.getParentVO()).getPk_tradetype();
                djlxbm = NCLocator.getInstance().lookup(IBilltypeService.class).getBilltypeCode(tradetypePk);
            }
            Object retObj = null;
            HashMap<String, String> paramMap = new HashMap<String, String>();
            paramMap.put(PfUtilBaseTools.PARAM_SILENTLY, PfUtilBaseTools.PARAM_SILENTLY);
            // String actionCode = IVSaleUtil.getActionCode((String)
            // billVO.getParentVO().getAttributeValue(IVApplicationHeadVO.PK_ORG));
            String cuserid = InvocationInfoProxy.getInstance().getUserId();
            UFDateTime currTime = new UFDateTime(InvocationInfoProxy.getInstance().getBizDateTime());
            WorkflownoteVO noteVO = null;
            try {
                noteVO =
                        ((IWorkflowMachine)NCLocator.getInstance().lookup(IWorkflowMachine.class)).checkWorkFlow(
                                IPFActionName.SAVE, djlxbm, billVO, null);
            } catch (BusinessException e) {
                SSCIVMLogger.error(e.getMessage(), e);
            }
            boolean hasWorkfFlow = false;
            if (noteVO == null) {
                try{
                    IFlowBizItf fbi = PfMetadataTools.getBizItfImpl(billVO, IFlowBizItf.class);

                    IWorkflowDefine wfDefine = NCLocator.getInstance().lookup(IWorkflowDefine.class);
                    hasWorkfFlow = wfDefine.hasValidProcessDef(((IVApplicationHeadVO)billVO.getParentVO()).getPk_org(),
                            ((IVApplicationHeadVO)billVO.getParentVO()).getTranstypecode(), fbi.getPkorg(), fbi.getBillMaker(), fbi.getEmendEnum(),WorkflowTypeEnum.Workflow.getIntValue());
                    if(!hasWorkfFlow){
                        hasWorkfFlow = wfDefine.hasValidProcessDef(InvocationInfoProxy.getInstance().getGroupId(),
                                ((IVApplicationHeadVO)billVO.getParentVO()).getTranstypecode(), fbi.getPkorg(), fbi.getBillMaker(), fbi.getEmendEnum(),WorkflowTypeEnum.Workflow.getIntValue());
                    }
                }catch (PFBusinessException e){
                    String err = NCLangRes4VoTransl.getNCLangRes().getStrByID("pfworkflow", "UPPpfworkflow-000058");/** 找不到工作流定义 无法启动工作流*/
                    if (e.getMessage()!=null && e.getMessage().contains(err)) {
                        //throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0027")/*@res "找不到流程定义，无法启动流程!"*/);
                    }else{
                        throw new PFBusinessException(e);
                    }
                }
                if (!hasWorkfFlow) {
                    ((IVApplicationHeadVO)billVO.getParentVO()).setApprover(cuserid);
                    ((IVApplicationHeadVO)billVO.getParentVO()).setApprovedate(currTime);
                    ((IVApplicationHeadVO)billVO.getParentVO()).setBillstatus(IBillStatus.CHECKPASS);
//            		((IVApplicationHeadVO)billVO.getParentVO()).setStatus(VOStatus.UPDATED);
//            		retObj = this.updateBatch(new IVApplicationAggVO[] { (IVApplicationAggVO) billVO }, null)[0];
                    UFDate preDate = ((IVApplicationHeadVO)billVO.getParentVO()).getPreparedate();
                    if (preDate.toStdString().substring(0, 10).compareTo(currTime.toStdString().substring(0,10)) > 0){
                        throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0", "01058sal-0150")/*"审批日期不能早于申请日期,请您切换业务日期再审批!"*/);
                    }
                    retObj = approveVOs(new IVApplicationAggVO[] { (IVApplicationAggVO) billVO });

                } else {
                    retObj = commitScriptPFlow(IPFActionName.START, djlxbm, billVO, assingUsers);
                }
            } else {
                // 有审批流走审批流
                retObj = commitScriptPFlow(IPFActionName.SAVE, djlxbm, billVO, assingUsers);
            }

            if (retObj == null) {
                result = new MessageVO(billVO, ActionUtils.COMMIT);
                result.setSuccess(false);
                result
                        .setErrorMessage(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("2011", "UPP2011-000339")/*
                         * @
                         * res
                         * "用户取消操作"*/);
            } else {
                if(retObj instanceof Map){
                    return retObj;
                }
                if (retObj instanceof AggregatedValueObject) {// 仅提交
                    result = new MessageVO((AggregatedValueObject)retObj, ActionUtils.COMMIT);
                } else if (retObj instanceof MessageVO[]) {// 提交并审批的情况会出现
                    MessageVO[] messages = (MessageVO[])retObj;
                    result = messages[0];
                } else if (retObj instanceof MessageVO) {
                    result = (MessageVO)retObj;
                }else if (retObj instanceof PfProcessBatchRetObject) {
                    if ((PfProcessBatchRetObject) retObj != null && ((PfProcessBatchRetObject) retObj).getRetObj() != null) {
                        result = (MessageVO) ((PfProcessBatchRetObject) retObj).getRetObj()[0];
                    } else {
                        result = new MessageVO(null, ActionUtils.COMMIT);
                    }
                }
            }

        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }

        return result;
    }

    private Object commitScriptPFlow(String actionName, String djlxbm, AggregatedValueObject aggVo, Object assingUsers) throws BusinessException {
        JSONObject assignContent = new JSONObject();
        HashMap<Object, Object> eParam = new HashMap<Object, Object>();
        if ((assingUsers instanceof LinkedTreeMap)) {
            assignContent = JSON.parseObject(new Gson().toJson(assingUsers));
            eParam.put("content", assignContent);
        }
        // 调用平台接口
        eParam.put(PfUtilBaseTools.PARAM_SILENTLY, PfUtilBaseTools.PARAM_SILENTLY);
//		eParam.put("isSkipAssign", true);
        if (IPFActionName.START.equals(actionName)) {
            String checkman = "";
            BaseDAO dao = new BaseDAO();
            String sql = " SELECT  a.checkman  FROM PUB_WORKFLOWNOTE a  INNER JOIN PUB_WF_TASK b   ON  a.PK_WF_TASK = b.PK_WF_TASK WHERE a.billid ='"
                    + aggVo.getParentVO().getPrimaryKey()
                    + "' and a.actiontype='MAKEBILL' and b.REJECTTACHEACTIVITYID is not null and a.ischeck='N' ";
            Object obj = dao.executeQuery(sql, new ColumnProcessor());
            if (obj != null) {
                checkman = (String) obj;
                actionName = IPFActionName.SIGNAL + checkman;
            }
        }
        CloudPFlowContext context = new CloudPFlowContext();
        context.setActionName(actionName);
        context.setBillType(djlxbm);
        context.setBillVos(new AggregatedValueObject[] { aggVo });
        context.seteParam(eParam);

        Object[] ss = null;
        if(IPFActionName.START.equals(actionName)){
            WorkflownoteVO noteVO = null;
            try {
                noteVO =
                        ((IWorkflowMachine)NCLocator.getInstance().lookup(IWorkflowMachine.class)).checkWorkFlow(
                                IPFActionName.START, djlxbm, aggVo, null);
            } catch (BusinessException e) {
                SSCIVMLogger.error(e.getMessage(), e);
            }
            WorkflowTypeEnum flowtype = nc.bs.pub.pf.PfUtilTools.runningFlowStatus(nccloud.commons.lang.StringUtils.isNotEmpty(context.getTrantype()) ? context.getTrantype() : context.getBillType(), aggVo.getParentVO().getPrimaryKey());
            if(flowtype == null){
                if(noteVO == null || noteVO.getTaskInfo().getAssignableInfos().size() == 0){
                    ss =NCLocator.getInstance().lookup(ICloudScriptPFlowService.class).exeScriptPFlow_CommitNoFlowBatch(context);
                }
            }
        }
        if(ss==null){
            ss =NCLocator.getInstance().lookup(ICloudScriptPFlowService.class).exeScriptPFlow(context);
        }

        Object obj = ss[0];
        if (((obj instanceof Map))
                && (((Map<?, ?>)obj).get("workflow") != null)
                && (("approveflow".equals(String.valueOf(((Map<?, ?>)obj).get("workflow")))) || ("workflow".equals(String
                .valueOf(((Map<?, ?>)obj).get("workflow")))))) {
            @SuppressWarnings("unchecked")
            Map<String, Object> map = (Map<String, Object>)obj;
            if (map.get("workflow") != null) {
                return map;
            }
        }
        return obj;
    }

    @Override
    public IVApplicationAggVO[] recall(IVApplicationAggVO[] clientBills, IVApplicationAggVO[] originBills) throws BusinessException {
        //判断saga状态
        if(clientBills != null && clientBills.length > 0) {
            String[] pks = new String[clientBills.length];
            for (int i = 0; i < clientBills.length; i++) {
                pks[i] = clientBills[i].getParentVO().getPk_ivapplication();
            }

            IVMSagaValidationUtils.checkSagaStatus(pks, IVApplicationHeadVO.getDefaultTableName(), IVApplicationHeadVO.PK_IVAPPLICATION);
        }
        List<IVApplicationAggVO> retvos = new ArrayList<IVApplicationAggVO>();
        try {
            for (int i = 0; i < clientBills.length; i++) {
                AggregatedValueObject billVO = clientBills[i];
                if(clientBills[i].getParentVO().getBillstatus()!=IBillStatus.COMMIT && clientBills[i].getParentVO().getBillstatus()!=IBillStatus.CHECKPASS){
                    //存在非自由态的单据
                    throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0025")/*@res "第:"*/+(i+1)+nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0028")/*@res "行，非提交态的单据不允许收回!"*/);
                }
                List<IVApplogVO> applogVOList =
                        NCLocator.getInstance().lookup(ApplicationLogService.class)
                                .queryApplicationLogByLyid(TransSpiltMergePksUtil.transIvapplicationToLyid(new String[] {clientBills[i].getParentVO().getPk_ivapplication()}));

                if(applogVOList != null && applogVOList.size() > 0){
                    throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0029")/*@res "单据"*/ + clientBills[i].getParentVO().getBillno()
                            + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0030")/*@res "已经开票，不允许取消审批!"*/);
                }
                Object retObj = doNccRecall(billVO);

                retvos.add( (IVApplicationAggVO) ((MessageVO) retObj).getSuccessVO());
            }
        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            ExceptionUtils.marsh(e);
        }
        return retvos.toArray(new IVApplicationAggVO[retvos.size()]);
    }

    private Object doNccRecall(AggregatedValueObject billVO) throws Exception {
        MessageVO result = null;

        IVApplicationQueryService ivApplicationQueryService = NCLocator.getInstance().lookup(IVApplicationQueryService.class);

        String djlxbm = null;
        try {
            if (billVO.getParentVO() instanceof IVApplicationHeadVO) {
                IVApplicationAggVO[] submitVos = ivApplicationQueryService.queryAggVOsByPks(new String[] { ((IVApplicationHeadVO) billVO
                        .getParentVO()).getPrimaryKey() });
                if (submitVos != null && submitVos.length > 0) {
                    if (null == ((IVApplicationHeadVO) billVO.getParentVO()).getTs()
                            || ((IVApplicationHeadVO) billVO.getParentVO()).getTs().compareTo(submitVos[0].getParentVO().getTs()) != 0) {
                        throw new Exception(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0", "01058sal-0057")/*@res "单据已经被他人修改,请刷新页面!"*/);
                    }
                }

                String tradetypePk = ((IVApplicationHeadVO) billVO.getParentVO()).getPk_tradetype();
                djlxbm = NCLocator.getInstance().lookup(IBilltypeService.class).getBilltypeCode(tradetypePk);
            }

            String actionName = IPFActionName.RECALL;

            boolean isApproveflowFlag = IVSaleUtil.isApproveFlowStartup(billVO.getParentVO().getPrimaryKey(), djlxbm);
            if (isApproveflowFlag) {
                actionName = IPFActionName.UNSAVE;
            }

            // 收回流程信息
            Object[] exeScriptPFlow = null;
            CloudPFlowContext context = new CloudPFlowContext();
            context.setActionName(actionName);
            context.setBillType(djlxbm);// 开票申请单
            context.setBillVos(new AggregatedValueObject[] { billVO });
            context.seteParam(new HashMap<Object, Object>());

            WorkflowTypeEnum flowtype = nc.bs.pub.pf.PfUtilTools.runningFlowStatus(nccloud.commons.lang.StringUtils.isNotEmpty(context.getTrantype()) ? context.getTrantype() : context.getBillType(), billVO.getParentVO().getPrimaryKey());

            ICloudScriptPFlowService service = NCLocator.getInstance().lookup(ICloudScriptPFlowService.class);

            if (flowtype == null) {
                // 一个制单环节
                exeScriptPFlow = service.exeScriptPFlow_UnSaveNoFlowBatch(context);

            } else {
                // 多个制单环节
                exeScriptPFlow = service.exeScriptPFlow(context);
            }

            if (exeScriptPFlow[0] instanceof PfProcessBatchRetObject) {
                if ((PfProcessBatchRetObject) exeScriptPFlow[0] != null && ((PfProcessBatchRetObject) exeScriptPFlow[0]).getRetObj() != null) {
                    result = new MessageVO((AggregatedValueObject) ((PfProcessBatchRetObject) exeScriptPFlow[0]).getRetObj()[0], ActionUtils.RECALL);
                } else {
                    result = new MessageVO(null, ActionUtils.RECALL);
                }
            } else if (exeScriptPFlow[0] instanceof AggregatedValueObject) {
                result = new MessageVO((AggregatedValueObject) (exeScriptPFlow[0]), ActionUtils.RECALL);
            }

        } catch (Exception e) {
            SSCIVMLogger.error(e.getMessage(), e);
            throw e;
        }

        return result;
    }




    /**
     * 开票申请-初始化默认数据
     * @param ivapplicationaggvo
     * @return
     * @throws BusinessException
     */
    public IVApplicationAggVO dealDefValue(String uistate, String pk_group,
                                           String pk_user, String pk_tradetype,
                                           String appcode) throws Exception {
        IVApplicationAggVO retvos = new IVApplicationAggVO();
        IVApplicationBillDefValue billDefValue = new IVApplicationBillDefValue();
        // 自定义默认值
        if (IVAWebConst.INIT_LOADDEF.equals(uistate) || IVAWebConst.UISTATUS_ADD.equals(uistate)) {
            retvos = billDefValue.getNewVO(pk_group, pk_user, pk_tradetype, appcode);
        } else if (IVAWebConst.CHANGE_LOADDEF.equals(uistate) || IVAWebConst.UISTATUS_EDIT.equals(uistate)) {
            //retvos = billDefValue.getDefaultVO(pk_org);
        }
        return retvos;
    }

    /**
     * 开票申请-查询组织本币对应币种
     * @param String
     * @return
     * @throws BusinessException
     */
    public String getOrgLocalCurrPK(String pk_org) throws BusinessException {
        String orgLocalCurrPK = CurrencyRateUtilHelper.getInstance().getLocalCurrtypeByOrgID(pk_org);
        return orgLocalCurrPK;
    }

    /**
     * 开票申请-币种对应精度
     * @param String
     * @return
     * @throws BusinessException
     */
    public Integer getCurrDigit(String pk_currtype) throws BusinessException {
        if (StringUtils.isEmpty(pk_currtype)) {
            return 0;
        }

        CurrtypeVO currtypeVO = null;
        if (RuntimeEnv.getInstance().isRunningInServer()) {
            currtypeVO = CurrtypeQuery.getInstance().getCurrtypeVO(pk_currtype);
        }
        return currtypeVO == null ? 0 : currtypeVO.getCurrdigit();
    }

    /**
     * 开票申请-获取组织对应版本
     * @param String
     * @return
     * @throws BusinessException
     */
    public String getOrgVersion(String voclassname, String name, String pk_org) throws Exception {
        OrgVO[] vos = OrgQueryUtil.queryOrgVOByPks(new String[]{pk_org});
        return vos[0].getPk_vid();
    }

    @Override
    public MessageVO[] approveVOs(IVApplicationAggVO[] applicationAggVOs) throws Exception {
        if (applicationAggVOs == null || applicationAggVOs.length == 0) {
            return null;
        }

        // 1、更新单据
        for (int i = 0; i < applicationAggVOs.length; i++) {
            applicationAggVOs[i].getParentVO().setStatus(VOStatus.UPDATED);
        }
        IVApplicationAggVO[] aggVOs = updateBatch(applicationAggVOs, null);

        MessageVO[] msgs = new MessageVO[aggVOs.length];
        for (int i = 0; i < aggVOs.length; i++) {
            msgs[i] = new MessageVO(aggVOs[i], ActionUtils.AUDIT);
        }
        //新增审批通过后事件
        EventDispatcher.fireEvent(new ApplicationBusinessEvent(IVAWebConst.MDID, IVApplicationEventType.TYPE_APPROVE_AFTER, aggVOs));

        // 2、审批通过时自动开票
        IVApplicationInvoiceService applicationInvoiceService = NCLocator.getInstance().lookup(IVApplicationInvoiceService.class);
        for (int i = 0; i < aggVOs.length; i++) {
            String billTypePk = aggVOs[i].getParentVO().getPk_tradetype();
            String billtypeCode = NCLocator.getInstance().lookup(IBilltypeService.class).getBilltypeCode(billTypePk);
            IVBilltypeVO billtypeVO = NCLocator.getInstance().lookup(IVABilltypeExtService.class).getBilltypeVOByCode(billtypeCode,
                    InvocationInfoProxy.getInstance().getGroupId());
            //增加小规模纳税人1%，3%税率说明校验@税率说明红冲原因@
            if(null != billtypeVO && IVApplicationSlsmUtil.slsmCheck(aggVOs[i])){
                if(billtypeVO.getIsatuo_invoice() == UFBoolean.TRUE){
                    JSONObject jsonObj = new JSONObject();
                    IVApplicationAggVO[] voAfterMakeInvoice = applicationInvoiceService.makeInvoice(new IVApplicationAggVO[] {aggVOs[i]}, jsonObj, null, false);
                    msgs[i] = new MessageVO(voAfterMakeInvoice[0], ActionUtils.AUDIT);
                }
            }
        }

        return msgs;
    }

    @Override
    public Object unApproveVOs(IVApplicationAggVO[] applicationAggVOs) throws BusinessException {
        if (applicationAggVOs == null || applicationAggVOs.length == 0) {
            return null;
        }

        // 1、判断开票申请单是否已经开票，如果已经开票，则不允许取消审批
        for (int i = 0; i < applicationAggVOs.length; i++) {
            List<IVApplogVO> applogVOList =
                    NCLocator.getInstance().lookup(ApplicationLogService.class)
                            .queryApplicationLogByLyid(TransSpiltMergePksUtil.transIvapplicationToLyid(new String[] {applicationAggVOs[i].getParentVO().getPk_ivapplication()}));

            if(applogVOList != null && applogVOList.size() > 0){
                throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0029")/*@res "单据"*/ + applicationAggVOs[i].getParentVO().getBillno()
                        + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0030")/*@res "已经开票，不允许取消审批!"*/);
            }
            applicationAggVOs[i].getParentVO().setStatus(VOStatus.UPDATED);
        }

        // 2、更新单据状态
        IVApplicationAggVO[] aggVOs = updateBatch(applicationAggVOs, null);

        MessageVO[] msgs = new MessageVO[aggVOs.length];
        for (int i = 0; i < aggVOs.length; i++) {
            msgs[i] = new MessageVO(aggVOs[i], ActionUtils.UNAUDIT);
        }
        //新增取消审批通过后事件
        EventDispatcher.fireEvent(new ApplicationBusinessEvent(IVAWebConst.MDID, IVApplicationEventType.TYPE_UNAPPROVE_AFTER, aggVOs));
        return msgs;
    }

    @Override
    public IVApplicationAggVO copyApplication(String pk) throws Exception {
        // 1、校验单据是否存在
        IVApplicationAggVO aggVO = NCLocator.getInstance().lookup(IVApplicationQueryService.class).queryByPK(pk);
        if (aggVO == null) {
            throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0", "01058sal-0057")/*@res "单据已经被他人修改,请刷新页面!"*/);
        }
        if(aggVO.getParentVO().getHzfp() == UFBoolean.TRUE || aggVO.getParentVO().getZffp() == UFBoolean.TRUE){
            throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0031")/*@res "单据关联的发票是红字发票或作废发票，不允许复制单据!"*/);
        }
        if(aggVO.getParentVO().getSrc_pkbusibill() != null){
            throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1058sal_0","01058sal-0032")/*@res "单据已关联上游单据，不允许复制单据!"*/);
        }

        // 2、复制单据
        IVApplicationAggVO copyVo = aggVO.clone();
        IVApplicationHeadVO headvo = copyVo.getParentVO();

        // 3、清除表头不该复制的字段
        //清除saga相关的三个字段，否则复制时出现主键被加锁的情况
        String[] headFieldNotCopy =
                {IVApplicationHeadVO.PK_IVAPPLICATION, IVApplicationHeadVO.APPROVEDATE, IVApplicationHeadVO.APPROVER,
                        IVApplicationHeadVO.BILLNO, IVApplicationHeadVO.BILLSTATUS, IVApplicationHeadVO.CREATIONTIME,
                        IVApplicationHeadVO.CREATOR, IVApplicationHeadVO.KPR, IVApplicationHeadVO.KPZT,
                        IVApplicationHeadVO.LYID, IVApplicationHeadVO.MODIFIEDTIME, IVApplicationHeadVO.MODIFIER,
                        IVApplicationHeadVO.PREPAREDATE, IVApplicationHeadVO.SRC_BILLNO,
                        IVApplicationHeadVO.SRC_PKBUSIBILL, IVApplicationHeadVO.SRC_TRADETYPE,IVApplicationHeadVO.SAGA_FROZEN,
                        IVApplicationHeadVO.SAGA_GTXID,IVApplicationHeadVO.SAGA_BTXID,IVApplicationHeadVO.SAGA_STATUS,
                        IVApplicationHeadVO.INVOICED_HJJE,IVApplicationHeadVO.INVOICED_HJSE,IVApplicationHeadVO.INVOICED_JSHJ,
                        IVApplicationHeadVO.INVOICEING_HJJE,IVApplicationHeadVO.INVOICEING_HJSE,IVApplicationHeadVO.INVOICEING_JSHJ,
                        IVApplicationHeadVO.CANINVOICE_HJJE,IVApplicationHeadVO.CANINVOICE_HJSE,IVApplicationHeadVO.CANINVOICE_JSHJ,IVApplicationHeadVO.HZXXSQB,IVApplicationHeadVO.EMAIL,IVApplicationHeadVO.SLSM};

        for (int i = 0; i < headFieldNotCopy.length; i++) {
            headvo.setAttributeValue(headFieldNotCopy[i], null);
        }

        // 4、清除表体字段
        Set<String> meterialPKs = new HashSet<String>(); //物料主键
        for (int i = 0; i < copyVo.getChildrenVO().length; i++) {
            IVApplicationBodyVO bodyVO = (IVApplicationBodyVO) copyVo.getChildrenVO()[i];
            bodyVO.setPk_ivappdetail(null);
            bodyVO.setPk_ivapplication(null);
            bodyVO.setCaninvoice_se(UFDouble.ZERO_DBL);
            bodyVO.setCaninvoice_xmje(UFDouble.ZERO_DBL);
            bodyVO.setCaninvoice_xmjshj(UFDouble.ZERO_DBL);
            bodyVO.setCaninvoice_xmsl(UFDouble.ZERO_DBL);
            bodyVO.setInvoiced_se(UFDouble.ZERO_DBL);
            bodyVO.setInvoiced_xmje(UFDouble.ZERO_DBL);
            bodyVO.setInvoiced_xmjshj(UFDouble.ZERO_DBL);
            bodyVO.setInvoiced_xmsl(UFDouble.ZERO_DBL);
            bodyVO.setInvoiceing_se(UFDouble.ZERO_DBL);
            bodyVO.setInvoiceing_xmje(UFDouble.ZERO_DBL);
            bodyVO.setInvoiceing_xmjshj(UFDouble.ZERO_DBL);
            bodyVO.setInvoiceing_xmsl(UFDouble.ZERO_DBL);
            if (bodyVO.getPk_materiel() != null){
                meterialPKs.add(bodyVO.getPk_materiel());
            }

            if(bodyVO.getFphxz() != null && IVAplocationFPXZ.FPXZ_ZCH.toIntValue() == bodyVO.getFphxz()) {
                bodyVO.setHh(null);
                bodyVO.setZkhhh(null);
            }
        }
        // 5、清除特殊票种相关字段
        if(copyVo.getIvTspzsBodyVO()!=null){
            for (int i = 0; i < copyVo.getIvTspzsBodyVO().length; i++) {
                IVTspzsBodyVO ivTspzsBodyVO =  copyVo.getIvTspzsBodyVO()[i];
                ivTspzsBodyVO.setPk_ivtspzsdetail(null);
                ivTspzsBodyVO.setPk_ivapplication(null);
                ivTspzsBodyVO.setPk_ivappdetail(null);
            }
        }

        //查询物料来源
        if (meterialPKs.size() > 0){
            Map<String, String> meterialMap = new HashMap<String, String>();//物料关联关系
            MaterialVO[]  materialVOS = NCLocator.getInstance().lookup(IMaterialBaseInfoQueryService.class).queryDataByPks(meterialPKs.toArray(new String[0]));
            meterialPKs.clear();
            for (MaterialVO materialVO : materialVOS){
                meterialPKs.add(materialVO.getPk_source());
                meterialMap.put(materialVO.getPk_material(), materialVO.getPk_source());
            }
            Map<String, MaterialVersionVO> map = NCLocator.getInstance().lookup(IMaterialPubService.class).queryMaterialBaseInfoByOidPks(meterialPKs.toArray(new String[0]),new String[]{MaterialVO.PK_MATERIAL});
            for (int i = 0; i < copyVo.getChildrenVO().length; i++){
                IVApplicationBodyVO bodyVO = (IVApplicationBodyVO) copyVo.getChildrenVO()[i];
                if (bodyVO.getPk_materiel() != null){
                    bodyVO.setPk_materiel(map.get(meterialMap.get(bodyVO.getPk_materiel())).getPk_material());
                }
            }
        }


        // 5、重新制单人、修改人、时间等信息
        String cuserid = InvocationInfoProxy.getInstance().getUserId();
        UFDateTime currTime = new UFDateTime(InvocationInfoProxy.getInstance().getBizDateTime());
        UFDate currDate = currTime.getDate();

        headvo.setBillstatus(IBillStatus.FREE);
        headvo.setPreparedate(currDate);
        headvo.setCreator(cuserid);
        headvo.setCreationtime(currTime);
        headvo.setModifier(cuserid);
        headvo.setModifiedtime(currTime);
        headvo.setHzfp(UFBoolean.FALSE);
        headvo.setCkfp(UFBoolean.FALSE);
        headvo.setZffp(UFBoolean.FALSE);
        headvo.setFpdm("");
        headvo.setFphm("");
        //表头设置开票方式默认值，默认为1 直联开票
        Integer paramValue = SysInitQuery.getParaInt(headvo.getPk_org(), IVAWebConst.IVA_KP_SSCIVA01);
        headvo.setKpfs(paramValue == null ? IVAplocationKPFS.ZLKP.toIntValue() : paramValue);

        //查客户版本并赋值
        Map<String, UFDate> map = new HashMap<String, UFDate>();
        map.put(headvo.getPk_customer(), headvo.getPreparedate());
        Map<String,String> idMap =  NCLocator.getInstance().lookup(ICustomerPubService.class).getCustomerLastVIDByOidAndDate(map);
        headvo.setPk_customer_v(idMap.get(headvo.getPk_customer()));

        for (int i = 0; i < copyVo.getChildrenVO().length; i++) {
            IVApplicationBodyVO bodyvo = (IVApplicationBodyVO) copyVo.getChildrenVO()[i];
            bodyvo.setStatus(VOStatus.NEW);
        }

        return copyVo;
    }

    @Override
    public boolean isFlowCheckman(String billId, String billType, String userId)
            throws BusinessException {
        return IVSaleUtil.isCheckman(billId, billType, userId);
    }

    @Override
    public IVApplicationAggVO calHeadJe(IVApplicationAggVO vo)
            throws BusinessException {
        UFDouble hjje = UFDouble.ZERO_DBL; //无税金额
        UFDouble hjse = UFDouble.ZERO_DBL; //税额
        UFDouble jshj = UFDouble.ZERO_DBL; //价税合计
        UFDouble can_hjje = UFDouble.ZERO_DBL; //可开无税金额
        UFDouble can_hjse = UFDouble.ZERO_DBL; //可开税额
        UFDouble can_jshj = UFDouble.ZERO_DBL; //可开价税合计

        //累加金额，删除行除外
        for (IVApplicationBodyVO bvo : vo.getBodyVOs()){
            if (bvo.getStatus() == VOStatus.DELETED){
                continue;
            }

            //取值
            UFDouble xmje = bvo.getXmje() == null ? UFDouble.ZERO_DBL : bvo.getXmje();
            UFDouble se = bvo.getSe() == null ? UFDouble.ZERO_DBL : bvo.getSe();
            UFDouble xmjshj = bvo.getXmjshj() == null ? UFDouble.ZERO_DBL : bvo.getXmjshj();
            UFDouble can_xmje = bvo.getCaninvoice_xmje() == null ? UFDouble.ZERO_DBL : bvo.getCaninvoice_xmje();
            UFDouble can_se = bvo.getCaninvoice_se() == null ? UFDouble.ZERO_DBL : bvo.getCaninvoice_se();
            UFDouble can_xmjshj = bvo.getCaninvoice_xmjshj() == null ? UFDouble.ZERO_DBL : bvo.getCaninvoice_xmjshj();

            //累加
            hjje = hjje.add(xmje);
            hjse = hjse.add(se);
            jshj = jshj.add(xmjshj);
            can_hjje = can_hjje.add(can_xmje);
            can_hjse = can_hjse.add(can_se);
            can_jshj = can_jshj.add(can_xmjshj);
        }

        //重新赋值
        IVApplicationHeadVO headvo = vo.getHeadVO();
        headvo.setHjje(hjje);
        headvo.setHjse(hjse);
        headvo.setJshj(jshj);
        headvo.setCaninvoice_hjje(can_hjje);
        headvo.setCaninvoice_hjse(can_hjse);
        headvo.setCaninvoice_jshj(can_jshj);
        return vo;
    }

}