package com.brilliance.isc.common.transaction;

import cn.hutool.core.util.ObjectUtil;
import com.brilliance.isc.bo.*;
import com.brilliance.isc.bo.model.*;
import com.brilliance.isc.common.api.bch.service.BchService;
import com.brilliance.isc.common.bopset.service.*;
import com.brilliance.isc.common.bptbck.service.BptbckService;
import com.brilliance.isc.common.component.SptDataComponent;
import com.brilliance.isc.common.contants.CommonContants;
import com.brilliance.isc.common.context.AppEnv;
import com.brilliance.isc.common.context.BopContext;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.converter.BaseComponentBuilder;
import com.brilliance.isc.common.converter.DtoMapper;
import com.brilliance.isc.common.counter.service.CounterService;
import com.brilliance.isc.common.dftcre.service.DftcreService;
import com.brilliance.isc.common.exception.CommonServiceException;
import com.brilliance.isc.common.glemod.service.GlemodService;
import com.brilliance.isc.common.glemod.vo.GlemodVo;
import com.brilliance.isc.common.jshmod.vo.JshmodRequest;
import com.brilliance.isc.common.lgbdet.service.LgbdetService;
import com.brilliance.isc.common.lgbdet.vo.LgbdetVo;
import com.brilliance.isc.common.liaall.service.LiaallService;
import com.brilliance.isc.common.liaall.vo.LiaallVo;
import com.brilliance.isc.common.liaallg.vo.LiaallgVo;
import com.brilliance.isc.common.liaccv.service.LiaccvService;
import com.brilliance.isc.common.liaccv.vo.LiaccvVo;
import com.brilliance.isc.common.limmod.service.LimOptionService;
import com.brilliance.isc.common.limmod.service.YpnmodService;
import com.brilliance.isc.common.limmod.vo.LimmodVo;
import com.brilliance.isc.common.limmod.vo.YpnmodVo;
import com.brilliance.isc.common.lock.BizLocker;
import com.brilliance.isc.common.lock.LockInfo;
import com.brilliance.isc.common.lock.common.BizRepeatComponent;
import com.brilliance.isc.common.monmod.vo.MonmodVo;
import com.brilliance.isc.common.oit.service.OitenTryService;
import com.brilliance.isc.common.quemod.service.QuemodService;
import com.brilliance.isc.common.quemod.vo.TaskStatus;
import com.brilliance.isc.common.quemod.vo.TrnRelflgStatus;
import com.brilliance.isc.common.rmbbop.vo.Rmb2101;
import com.brilliance.isc.common.rmbbop.vo.Rmb2112;
import com.brilliance.isc.common.rmbbop.vo.RmbbopRequest;
import com.brilliance.isc.common.setfeg.service.SetfegService;
import com.brilliance.isc.common.setmod.service.SetmodService;
import com.brilliance.isc.common.setmod.vo.SetmodVo;
import com.brilliance.isc.common.sysmod.SysmodService;
import com.brilliance.isc.common.taskdistributor.service.TaskDistService;
import com.brilliance.isc.common.tools.service.ObjectStroeToolService;
import com.brilliance.isc.common.transaction.cecm.service.impl.CecmBatchStoreExecuteServiceImpl;
import com.brilliance.isc.common.transaction.help.TransactionHelpService;
import com.brilliance.isc.common.transaction.help.TransactionServiceSet;
import com.brilliance.isc.common.transaction.newcheck.bopdec.BopgatValidator;
import com.brilliance.isc.common.transaction.newcheck.bopdec.BoppayValidator;
import com.brilliance.isc.common.transaction.newcheck.bopdec.BopremValidator;
import com.brilliance.isc.common.transaction.newcheck.bopset.CfaValidator;
import com.brilliance.isc.common.transaction.newcheck.bopset.CfabopValidator;
import com.brilliance.isc.common.transaction.newcheck.bopset.JshmodValidator;
import com.brilliance.isc.common.transaction.newcheck.bopset.RmbbopValidator;
import com.brilliance.isc.common.transaction.newcheck.ecif.Ecif0958Validator;
import com.brilliance.isc.common.transaction.newcheck.glemod.GlemodValidator;
import com.brilliance.isc.common.transaction.newcheck.lgbdet.LgbdetValidator;
import com.brilliance.isc.common.transaction.newcheck.liaall.LiaallValidator;
import com.brilliance.isc.common.transaction.newcheck.liaccv.LiaccvValidator;
import com.brilliance.isc.common.transaction.newcheck.limmod.LimmodValidator;
import com.brilliance.isc.common.transaction.newcheck.monmod.MonmodValidator;
import com.brilliance.isc.common.transaction.newcheck.setmod.SetmodValidator;
import com.brilliance.isc.common.transaction.newcheck.trndia.TrndiaValidator;
import com.brilliance.isc.common.transaction.newcheck.trndoc.TrndocValidator;
import com.brilliance.isc.common.transaction.newcheck.umdmod.UmdmodValidator;
import com.brilliance.isc.common.transaction.txnhold.service.TxnHoldService;
import com.brilliance.isc.common.transaction.txnhold.vo.TxnHoldVo;
import com.brilliance.isc.common.transaction.vo.BaseTransactionVo;
import com.brilliance.isc.common.transaction.vo.TrnInfo;
import com.brilliance.isc.common.trndia.service.TrndiaService;
import com.brilliance.isc.common.trndia.vo.TrndiaVo;
import com.brilliance.isc.common.trndoc.service.TrndocService;
import com.brilliance.isc.common.trndoc.vo.TrndocVo;
import com.brilliance.isc.common.trnism.service.TrnismService;
import com.brilliance.isc.common.trnmod.service.TrnmodService;
import com.brilliance.isc.common.trnmod.vo.TrnmodVo;
import com.brilliance.isc.common.trtcre.service.TrtcreService;
import com.brilliance.isc.common.umdmod.service.UmdmodService;
import com.brilliance.isc.common.umdmod.vo.UmdmodVo;
import com.brilliance.isc.common.util.SettleExceptionUtils;
import com.brilliance.isc.common.util.StringUtils;
import com.brilliance.isc.common.util.Utils;
import com.brilliance.isc.common.vo.BizAmdInfoVo;
import com.brilliance.isc.common.vo.BizInfoVo;
import com.brilliance.isc.common.vo.SimpleModuleVo;
import com.brilliance.isc.common.wfmmod.service.WfmmodService;
import com.brilliance.isc.common.wfmmod.vo.WfmmodVo;
import com.brilliance.isc.constant.ErrorCode;
import com.brilliance.isc.doc.IGidTextFormat;
import com.brilliance.isc.exception.RestBizException;
import com.brilliance.isc.mda.dao.*;
import com.brilliance.isc.utils.ObjectUtils;
import com.brilliance.isc.utils.SpringUtils;
import com.brilliance.isc.vo.WarnVo;
import com.brilliance.isc.vo.component.bptbck.BptbckVo;
import com.brilliance.isc.warn.WarnService;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import com.brilliance.mda.runtime.mda.util.Strings;
import org.apache.commons.collections.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.util.*;

import static com.brilliance.mda.runtime.mda.Constants.NULLSTR;
import static com.brilliance.mda.runtime.mda.Constants.SptWaitingRegistration;

public abstract class AbstractTransactionService<T extends BaseTransactionVo> implements TransactionService<T> {

    protected Map<String, String> serviceRegisterMaps = new HashMap<>();
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Resource
    private TransactionHelpService transactionHelpService;

    @Resource
    private SetmodService setmodService;

    @Resource
    private TrndiaService trndiaService;

    @Resource
    private TrnismService trnismService;

    @Resource
    private CecmBatchStoreExecuteServiceImpl cecmBatchStoreExecuteServiceImpl;

    @Resource
    private TrnmodService trnmodService;

    @Resource
    private SysmodService sysmodService;

    @Resource
    private QuemodService quemodService;

    @Resource
    private TrndocService trndocService;

    @Resource
    private LiaallService liaallService;

    @Resource
    private LiaccvService liaccvService;

    @Resource
    private TrtcreService trtcreService;

    @Resource
    private DftcreService dftcreService;

    @Resource
    private BptbckService bptbckService;

    @Resource
    private CounterService counterService;

    @Resource
    private LiaallValidator liaallValidator;

    @Autowired
    private LgbdetValidator lgbdetValidator;

    @Resource
    private LiaccvValidator liaccvValidator;

    @Resource
    private LimmodValidator limmodValidator;

    @Resource
    private SetmodValidator setmodValidator;

    @Resource
    private GlemodValidator glemodValidator;

    @Resource
    private TrndocValidator trndocValidator;

    @Resource
    private MonmodValidator monmodValidator;

    @Resource
    private TrndiaValidator trndiaValidator;

    @Resource
    private CfabopValidator cfabopValidator;

    @Resource
    private CfaValidator cfaValidator;

    @Resource
    private BopgatValidator bopgatValidator;

    @Resource
    private BopremValidator bopremValidator;

    @Resource
    private BoppayValidator boppayValidator;

    @Resource
    private TxnHoldService txnHoldService;

    @Resource
    private UmdmodValidator umdmodValidator;

    @Resource
    private WarnService warnService;

    @Resource
    private TrnMapper trnMapper;

    @Resource
    private WfeMapper wfeMapper;

    @Resource
    private ErsMapper ersMapper;

    @Resource
    private FujianMapper fujianMapper;

    @Resource
    private ImgMapper imgMapper;

    @Resource
    private WfmmodService wfmmodService;

    @Resource
    private GlemodService glemodService;

    @Resource
    private SetfegService setfegService;

    @Resource
    private AppEnv appEnv;

    @Resource
    private UmdmodService umdmodService;

    @Resource
    private BchService bchService;

    @Resource
    private RmbbopService rmbbopService;

    @Resource
    private JshmodService jshmodService;

    @Resource(name = "limocc")
    private LimOptionService limoccservice;

    @Resource
    private TaskDistService taskDistService;

    @Resource
    private CfagitService cfagitService;

    @Resource
    private BizLocker bizLocker;

    @Resource
    private ObjectStroeToolService objectStroeToolService;
    @Resource
    private OitenTryService oitenTryService;

    @Resource
    private RmbbopValidator rmbbopValidator;

    @Resource
    private JshmodValidator jshmodValidator;

    @Resource
    private SptDataComponent sptDataComponent;

    @Resource
    private BizRepeatComponent bizRepeatComponent;

    @Resource
    private QueMapper queMapper;

    @Resource
    private YpnmodService ypnmodService;

    @Resource
    private BopgatService bopgatService;

    @Resource
    private BopremService bopremService;

    @Resource
    private BoppayService boppayService;

    @Resource
    private CfabopService cfabopService;

    @Autowired
    private LgbdetService lgbdetService;

    @Resource
    private Ecif0958Validator ecif0958Validator;

    @Resource
    private SmhMapper smhMapper;

    public boolean hasService(String service) {
        if ("Y".equals(serviceRegisterMaps.get(service))) {
            return true;
        }
        return false;
    }

    public void lock(String objtyp, String objinr) {
        if (!MdaUtils.isEmpty(objtyp) && !MdaUtils.isEmpty(objinr)) {
            //锁定业务数据
            objtyp = objtyp.toUpperCase();
            String tranName = SettleContext.getTransName().toUpperCase();
            LockInfo lockInfoObj = LockInfo.builder().objInr(objinr).objType(objtyp)
                    .trnName(tranName)
                    .usrId(SettleContext.getSessionUserVo().getLogName())
                    .reentrant(true)
                    .build();
            if (!bizLocker.lock(lockInfoObj)) {
                //锁定业务交易以失败
                logger.error("锁定业务交易失败[{}:{}]", objtyp, objinr);
                LockInfo lockInfo = bizLocker.getLock(lockInfoObj);
                if (lockInfo != null) {
                    throw new RestBizException(ErrorCode.LOCK_BIZ_FAIL, "该笔" + objtyp + ":" + objinr + "业务数据已被" + lockInfo.getUsrId() + "使用" + lockInfo.getTrnName() + "锁定");
                }
                throw new RestBizException(ErrorCode.LOCK_BIZ_FAIL, "锁定业务交易失败");
            }
            logger.info("锁定业务交易{}数据[{}:{}]成功", tranName, lockInfoObj.getObjType(), lockInfoObj.getObjInr());
        }
    }

    /**
     * 移除TransactionStoreSet,LiaallSet 防止内存泄漏，以及解锁处理
     */
    @Override
    public void afterSave(T transactionVo, boolean shouldReleaseLock) {
        logger.info("{}交易save完成后清理数据", transactionVo.getTransName());
        transactionHelpService.clearTransactionStoreSet();
        if (hasService(CommonContants.LIAALL_SERVICE)
                || hasService(CommonContants.LIACCV_SERVICE)) {
            transactionHelpService.clearLiaallSet();
        }
        if (hasService(CommonContants.SETMOD_SERVICE)) {
            setfegService.clearFeeSet();
        }
        if (hasService(CommonContants.TRNDOC_SERVICE)) {
            trndocService.clearCorTypeList();
        }
        if (shouldReleaseLock) {
            bizLocker.unlockAllOfTrans(SettleContext.getTransName(), SettleContext.getSessionUserVo().getLogName());
        }
    }

    /**
     * 存盘处理
     *
     * @param transactionVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public T saveTransaction(T transactionVo) {
        String transName = transactionVo.getTransName();
        StopWatch stopWatch = new StopWatch(transName + "整体保存性能分析");
//        trnmodService.troAddToLocktable( trnmodVo.getTrorescon(), obj, 3 );
        logger.info("{} Service预处理数据", transName);
        stopWatch.start("BeforeSave处理");
        this.beforeSave(transactionVo);
        stopWatch.stop();
        stopWatch.start("Save保存处理");
        boolean isSuccess = this.save(transactionVo);
        logger.info("交易保存结果{}", isSuccess);
        stopWatch.stop();
        logger.info("{} Service主附表数据完成", transName);
        stopWatch.start("afterSave");
        this.afterSave(transactionVo, isSuccess);
        stopWatch.stop();
        logger.info("{} Service数据缓存清理完成", transName);
        logger.info(stopWatch.prettyPrint());
        return transactionVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public T saveTransactionForAuto(T transactionVo) {
        String transName = transactionVo.getTransName();
        StopWatch stopWatch = new StopWatch(transName + "整体保存性能分析");
//        trnmodService.troAddToLocktable( trnmodVo.getTrorescon(), obj, 3 );
        logger.info("{} Service预处理数据", transName);
        stopWatch.start("BeforeSave处理");
        this.beforeSave(transactionVo);
        stopWatch.stop();
        stopWatch.start("Save保存处理");
        boolean isSuccess = this.save(transactionVo);
        logger.info("交易保存结果{}", isSuccess);
        stopWatch.stop();
        logger.info("{} Service主附表数据完成", transName);
        stopWatch.start("afterSave");
        this.afterSave(transactionVo, isSuccess);
        stopWatch.stop();
        logger.info("{} Service数据缓存清理完成", transName);
        logger.info(stopWatch.prettyPrint());
        return transactionVo;
    }

    /**
     * 1.公共模块的试算
     * 2.初始化trn值
     * 3.自身交易业务主表，pts存盘
     * 4.公共模块的存盘
     *
     * @param transactionVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(T transactionVo) {
        String transName = transactionVo.getTransName();
        StopWatch stopWatch = new StopWatch(transName.toUpperCase() + "交易Save性能分析");
        logger.info("{} Service开始保存数据", transName);
        stopWatch.start("重计算公共组件");
        calcCommonComponents(transactionVo);
        stopWatch.stop();
        stopWatch.start("检核交易以及公共组件");
        boolean checkFlag = saveWithCheck(transactionVo);
        if (!checkFlag) {
            logger.warn("{} Service后端检核失败", transName);
            bizRepeatComponent.releaseRepeatLock(transactionVo);
            return false;
        }
        checkFlag = this.otherCheck(transactionVo);
        if (!checkFlag) {
            logger.warn("{} 统一名单筛查后端检核失败", transName);
            bizRepeatComponent.releaseRepeatLock(transactionVo);
            return false;
        }
        stopWatch.stop();
        stopWatch.start("初始化Trn信息");
        logger.info("{} Service初始化Trn信息", transName);
        initTrnInfo(transactionVo);
        stopWatch.stop();
        T cloneTransactionVo = MdaUtils.deepClone(transactionVo);
        logger.info("{} Service执行交易下保存处理", transName);
        stopWatch.start("交易下保存");
        txnSave(transactionVo);
        stopWatch.stop();
        logger.info("{} Service完成交易下保存处理", transName);
        stopWatch.start("保存公共组件");
        saveCommonComponents(transactionVo);
        stopWatch.stop();
        this.storeTrndata(cloneTransactionVo);
        logger.info("{} Service完成交易所有保存处理", transName);
        logger.info(stopWatch.prettyPrint());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public T txnHold(T transactionVo) {
        String transName = transactionVo.getTransName();
        logger.info("{} Service执行暂存处理", transName);
        this.beforeSave(transactionVo);
        txnHoldService.txnHold(TxnHoldVo.builder().baseTransactionVo(transactionVo).build());
        this.afterSave(transactionVo, true);
        logger.info("{} Service完成暂存处理", transName);
        return transactionVo;
    }


    /**
     * 1.公共模块的试算
     * 2.自身交易检核
     * 3.公共模块检核
     *
     * @param transactionVo
     * @return
     */
    @Override
    public Map<String, String> check(T transactionVo) {
        calcCommonComponents(transactionVo);
        Map<String, String> maps = new HashMap<>();
        //增加ecif0958核验
        if (ecif0958Validator.isValidate()) {
            maps.putAll(ecif0958Validator.validate(transactionVo));
        }
        maps.putAll(txnCheck(transactionVo));
        maps.putAll(checkCommonComponents(transactionVo));
        logger.info("业务检核错误信息： {}", Utils.toPrettyJson(maps));
        return maps;
    }

    @Override
    public boolean warning(T transactionVo) {
        List<WarnVo> oldWarningList = transactionVo.getWarnList();
        boolean checkWarningBalance = warnService.checkWarningBalance(oldWarningList);
        transactionVo.setWarnList(warnService.getTotalWarns());
        logger.info("警告信息是否发生变化： {}", !checkWarningBalance);
        return checkWarningBalance;
    }

    /**
     * 公共模块的试算
     */
    public void calcCommonComponents(T transactionVo) {
        String transName = transactionVo.getTransName();
        StopWatch stopWatch = new StopWatch(transName + "交易组件重计算分析");
        logger.info("{} Service开始重计算数据", transName);
        stopWatch.start("摘要信息计算");
        TransactionServiceSet transactionServiceSet = transactionHelpService.getTransactionStoreSet();
        BizInfoVo bizInfoVo = buildBizInfo(transactionVo);
        BizAmdInfoVo bizAmdInfoVo = buildBizAmdInfo(transactionVo);
        stopWatch.stop();
        if (hasService(CommonContants.TRNMOD_SERVICE)) {
            logger.info("{} Serivce 计算Trnmod", transName);
            //build trnmod
            stopWatch.start("计算Trn");
            TrnmodVo trnmod = BaseComponentBuilder.buildTrnmodVo(sptDataComponent.loadSpt(transactionVo), sptDataComponent.loadSmh(transactionVo));
            trnmod.reset();
            transactionServiceSet.setTrnmodVo(trnmod);
            stopWatch.stop();
        }

        //试算保证金
        if (hasService(CommonContants.LIACCV_SERVICE)) {
            logger.info("{} Serivce 计算保证金Liaccv信息", transName);
            stopWatch.start("计算保证金");
            //build liaccv
//            LiaccvVo liaccv = BaseComponentBuilder.buildLiaccvVo(transactionVo.getLiaccvg(), buildBizInfo(transactionVo), bizAmdInfoVo, transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList());
            LiaccvVo liaccv = new LiaccvVo();
            liaccv.setLiaccvg(transactionVo.getLiaccvg());
            liaccv.setRec(buildBizInfo(transactionVo));
            liaccv.setAmdRec(bizAmdInfoVo);
            liaccv.setCbsMap(transactionServiceSet.getCbsMap());
            liaccv.setPtsList(transactionServiceSet.getPtsList());
            DtoMapper.INSTANCE.updateVoToBo(transactionVo.getLiaccv(), liaccv);
            liaccv.reset();
            transactionServiceSet.setLiaccvVo(liaccv);
            liaccvService.assertLiaccv(liaccv);
            transactionVo.setLiaccvg(liaccv.getLiaccvg());
            DtoMapper.INSTANCE.updateBoToVo(liaccv, transactionVo.getLiaccv());
            stopWatch.stop();
        }
        //试算表外 //Liaall.ruleMtabutSavN120()
        if (hasService(CommonContants.LIAALL_SERVICE)) {
            logger.info("{} Serivce 计算表外Liaall信息", transName);
            //build liaall
            stopWatch.start("计算表外");
            LiaallVo liaall = BaseComponentBuilder.buildLiaallVo(transactionVo.getLiaallg(), transactionVo.getLiaccvg(), buildBizInfo(transactionVo), bizAmdInfoVo, transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList());
            DtoMapper.INSTANCE.updateVoToBo(transactionVo.getLiaall(), liaall);
            liaall.reset();
            transactionServiceSet.setLiaall(liaall);
            liaallService.assertLIAALL(liaall);
            transactionVo.setLiaallg(liaall.getLiaallg());
            DtoMapper.INSTANCE.updateBoToVo(liaall, transactionVo.getLiaall());
            stopWatch.stop();
        }
        //试算二级福费廷额度管控LGBDET
        if (hasService(CommonContants.LGBDET_SERVICE)) {
            stopWatch.start("计算LGBDET");
            LgbdetVo lgbdet = BaseComponentBuilder.buildLgbdetVo(bizInfoVo, transactionServiceSet.getCbsMap());
            lgbdet.reset();
            lgbdetService.assertLgbdet(lgbdet);
            if ("E".equals(lgbdet.getErrsta()) && StringUtils.isNotEmpty(lgbdet.getErrmsg())) {
                throw new CommonServiceException(lgbdet.getErrmsg());
            }
            transactionServiceSet.setLgbdetVo(lgbdet);
            stopWatch.stop();
        }
        //试算额度
        if (hasService(CommonContants.LIMMOD_SERVICE)) {
            stopWatch.start("计算额度");
            logger.info("{} Serivce 计算额度", transName);
            LimmodVo limmodVo = BaseComponentBuilder.buildLimmodVo(bizInfoVo, bizAmdInfoVo, transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList(), transactionServiceSet.getLiaall(), transactionServiceSet.getLiaccvVo(), transactionVo);
            transactionServiceSet.setLimmodVo(limmodVo);
            limoccservice.assertLim(limmodVo);
            DtoMapper.INSTANCE.updateBoToVo(limmodVo, transactionVo.getLimmod());
            stopWatch.stop();
        }
        //试算押品
        if (hasService(CommonContants.YPNMOD_SERVICE)) {
            stopWatch.start("计算押品");
            logger.info("{} Serivce 计算押品", transName);
            YpnmodVo ypnmodVo = BaseComponentBuilder.buildYpnmodVo(bizInfoVo, transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList(), transactionVo);
            transactionServiceSet.setYpnmodVo(ypnmodVo);
            ypnmodService.assertYpn(ypnmodVo);
            DtoMapper.INSTANCE.updateBoToVo(ypnmodVo, transactionVo.getYpnmod());
            stopWatch.stop();
        }
        //试算面函报文  Mtabut.ruleSavN200()
        if (hasService(CommonContants.TRNDOC_SERVICE)) {
            stopWatch.start("计算报文面函");
            //build trndoc
            TrndocVo trndocVo = new TrndocVo();
            if (hasService(CommonContants.SETMOD_SERVICE)) {
                //为解决循环依赖的问题，先试算费用账务保证面函报文数据正确
                logger.info("{} Serivce 计算面函Trndoc信息之前试算费用账务", transName);
                SetmodVo setmodVo = BaseComponentBuilder.buildSetmodVo(bizInfoVo, bizAmdInfoVo, transactionServiceSet.getCbsMap(),
                        transactionServiceSet.getPtsList(), transactionVo.getSetfog(), transactionVo.getSetfeg(), transactionVo.getSetglg());
                DtoMapper.INSTANCE.updateVoToBo(transactionVo.getSetmod(), setmodVo);
                setmodVo.reset();
                if (hasService(CommonContants.LIAALL_SERVICE)) {
                    LiaallVo liaallVo = transactionServiceSet.getLiaall();
                    setmodVo.setLiaall(liaallVo);
                }
                if (hasService(CommonContants.LIACCV_SERVICE)) {
                    LiaccvVo liaccvVo = transactionServiceSet.getLiaccvVo();
                    setmodVo.setLiaccvVo(liaccvVo);
                }
                setmodVo.setDoceotList(transactionVo.getDoceot());
                setmodService.assertSetmod(setmodVo);
                //清掉缓存
                setfegService.clearFeeSet();
                trndocVo.setSetglg(setmodVo.getSetglg());
                trndocVo.setSetfeg(setmodVo.getSetfeg());
                trndocVo.setSetfog(setmodVo.getSetfog());
            }
            //先试算报送组件，赋值报送品种  境内外收入
            if (hasService(CommonContants.BOPSET_SZSB_BOPGAT_SERVICE)) {
                logger.info("{} Serivce 计算面函Trndoc信息之前判断收支申报境内外收入报送品种", transName);
                Bopgat bopgatvo = new Bopgat();
                if (!MdaUtils.isEmpty(transactionVo.getBopgat())) {
                    bopgatvo = transactionVo.getBopgat();
                }
                String szflg = bopgatvo.getSzflg();
                String basflg = bopgatvo.getBasflg();
                if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                    if ("1".equals(szflg)) {
                        trndocVo.setBoptyp("DBA");
                    } else if ("2".equals(szflg)) {
                        trndocVo.setBoptyp("DBD");
                    }
                } else {
                    trndocVo.setBoptyp("");
                }
            }

            // 先试算报送组件，赋值报送品种  境内外汇款
            if (hasService(CommonContants.BOPSET_SZSB_BOPREM_SERVICE)) {
                logger.info("{} Serivce 计算面函Trndoc信息之前判断收支申报境内外汇款报送品种", transName);
                Boprem bopremvo = new Boprem();
                if (!MdaUtils.isEmpty(transactionVo.getBoprem())) {
                    bopremvo = transactionVo.getBoprem();
                }
                String szflg = bopremvo.getSzflg();
                String basflg = bopremvo.getBasflg();
                if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                    if ("1".equals(szflg)) {
                        trndocVo.setBoptyp("DBB");
                    } else if ("2".equals(szflg)) {
                        trndocVo.setBoptyp("DBE");
                    }
                } else {
                    trndocVo.setBoptyp("");
                }
            }

            // 先试算报送组件，赋值报送品种  境内外承兑
            if (hasService(CommonContants.BOPSET_SZSB_BOPPAY_SERVICE)) {
                logger.info("{} Serivce 计算面函Trndoc信息之前判断收支申报境内外承兑报送品种", transName);
                Boppay boppayvo = new Boppay();
                if (!MdaUtils.isEmpty(transactionVo.getBoppay())) {
                    boppayvo = transactionVo.getBoppay();
                }
                String szflg = boppayvo.getSzflg();
                String basflg = boppayvo.getBasflg();
                if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                    if ("1".equals(szflg)) {
                        trndocVo.setBoptyp("DBC");
                    } else if ("2".equals(szflg)) {
                        trndocVo.setBoptyp("DBF");
                    }
                } else {
                    trndocVo.setBoptyp("");
                }
            }

            logger.info("{} Serivce 计算面函Trndoc信息", transName);
            trndocVo.setRec(bizInfoVo);
            trndocVo.setAmdRec(bizAmdInfoVo);
            trndocVo.setCbsMap(transactionServiceSet.getCbsMap());
            trndocVo.setPtsptas(MdaUtils.deepClone(transactionServiceSet.getPtsList()));
            trndocVo.setSpt(transactionVo.getSpt());
            trndocVo.setDoceot(transactionVo.getDoceot());
            trndocVo.reset();
            transactionServiceSet.setTrndocVo(trndocVo);
            trndocService.assertDOCS(trndocVo);
            transactionVo.setDoceot(trndocVo.getDoceot());
            stopWatch.stop();
        }
        //试算费用账务 //Setmod.ruleMtabutSavN10()
        if (hasService(CommonContants.SETMOD_SERVICE)) {
            stopWatch.start("计算费用账务");
            logger.info("{} Serivce 计算费用账务Setmod信息", transName);
            //build setmod
            SetmodVo setmodVo = BaseComponentBuilder.buildSetmodVo(bizInfoVo, bizAmdInfoVo, transactionServiceSet.getCbsMap(),
                    transactionServiceSet.getPtsList(), transactionVo.getSetfog(), transactionVo.getSetfeg(), transactionVo.getSetglg());
            DtoMapper.INSTANCE.updateVoToBo(transactionVo.getSetmod(), setmodVo);
            setmodVo.reset();
            transactionServiceSet.setSetmodVo(setmodVo);
            if (hasService(CommonContants.LIAALL_SERVICE)) {
                LiaallVo liaallVo = transactionServiceSet.getLiaall();
                setmodVo.setLiaall(liaallVo);
            }
            if (hasService(CommonContants.LIACCV_SERVICE)) {
                LiaccvVo liaccvVo = transactionServiceSet.getLiaccvVo();
                setmodVo.setLiaccvVo(liaccvVo);
            }
            if (hasService(CommonContants.TRNDOC_SERVICE)) {
                TrndocVo trndocVo = transactionServiceSet.getTrndocVo();
                setmodVo.setDoceotList(trndocVo.getDoceot());
                setmodVo.setParstm(trndocVo.getParstm());
            }
            setmodService.assertSetmod(setmodVo);
            transactionVo.setSetfog(setmodVo.getSetfog());
            transactionVo.setSetfeg(setmodVo.getSetfeg());
            transactionVo.setSetglg(setmodVo.getSetglg());
            DtoMapper.INSTANCE.updateBoToVo(setmodVo, transactionVo.getSetmod());
            //Setmod.ruleMtabutSavN199() 存盘时 检核牌价是否发生变化
            setmodService.checkXrtChg(setmodVo);
            stopWatch.stop();
        }
        if (hasService(CommonContants.GLEMOD_SERVICE)) {
            stopWatch.start("计算分录");
            logger.info("{} Serivce 计算分录Glemod信息", transName);
            //build glemod
            GlemodVo glemod = BaseComponentBuilder.buildGlemodVo(bizInfoVo, transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList());
            glemod.reset();
            if (hasService(CommonContants.LIAALL_SERVICE)) {
                LiaallVo liaallVo = transactionServiceSet.getLiaall();
                glemod.setLiaallg(liaallVo.getLiaallg());
            }
            if (hasService(CommonContants.SETMOD_SERVICE)) {
                SetmodVo setmodVo = transactionServiceSet.getSetmodVo();
                glemod.setSetfog(setmodVo.getSetfog());
                glemod.setSetfeg(setmodVo.getSetfeg());
                glemod.setSetglg(setmodVo.getSetglg());
                glemod.setRec(setmodVo.getRec());
            }
            glemodService.fillGLEStream(glemod);
            transactionVo.setGles(glemod.getGles());
            transactionServiceSet.setGlemodVo(glemod);
            stopWatch.stop();
        }
        //试算备忘录  Mtabut.ruleSavN200()
        if (hasService(CommonContants.TRNDIA_SERVICE)) {
            stopWatch.start("计算Diary");
            logger.info("{} Serivce 计算Diary记事簿 Trndia信息", transName);
            //build trndia
            TrndiaVo trndiaVo = BaseComponentBuilder.buildTrndiaVo(bizInfoVo, bizAmdInfoVo, transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList(), transactionVo);
            trndiaVo.reset();
            transactionServiceSet.setTrndiaVo(trndiaVo);
            trndiaService.assertDiaries(trndiaVo);
            transactionVo.setDias(trndiaVo.getDias());
            stopWatch.stop();
        }

        //试算人民币报送
        if (hasService(CommonContants.BOPSET_RMB_SERVICE)) {
            stopWatch.start("计算人民币申报信息");
            logger.info("{} Serivce 计算人民币申报信息", transName);
            RmbbopRequest<BizInfoVo, BizAmdInfoVo> rmbbopRequest = BaseComponentBuilder.buildRmbbopRequest(bizInfoVo, bizAmdInfoVo, transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList(), transactionServiceSet.getSetmodVo().getSetglg(), transactionVo);
            rmbbopRequest.reset();
            transactionServiceSet.setRmbbopRequest(rmbbopRequest);
            BopContext.load(rmbbopRequest);
            rmbbopService.calcRmbbop(rmbbopRequest.getRmbbop());
            Rmb2101 rmb2101 = rmbbopRequest.getRmbbop().getRmb2101();
            Rmb2112 rmb2112 = rmbbopRequest.getRmbbop().getRmb2112();
            rmb2112.getRecgrp().getAds().setLevyno(rmb2101.getRecgrp().getAds().getLevyno());
            if (rmb2112.getRecgrp().getTbz().size() == 1) {
                rmb2112.getRecgrp().getTbz().get(0).setReceamt(rmb2101.getRecgrp().getAds().getAllamt());
            }
            BopContext.remove();
            transactionVo.setRmbbop(rmbbopRequest.getRmbbop());
            stopWatch.stop();
        }

        //试算反洗钱
        if (hasService(CommonContants.FANXIQIAN_SERVICE)) {
            stopWatch.start("计算反洗钱信息");
            logger.info("{} Serivce 计算反洗钱信息", transName);
            MonmodVo monmodVo = BaseComponentBuilder.buildMonmodRequest(bizInfoVo,transactionServiceSet.getPtsList(), transactionServiceSet.getSetmodVo().getSetglg());
            monmodVo.setPtyinr(getPtyinr(transactionVo));
            monmodVo.setDowngradeMsg(downgradeMsg(transactionVo));
            monmodVo.setForexmod(transactionVo.getForexmod());
            transactionServiceSet.setMonmodVo(monmodVo);
            stopWatch.stop();
        }

        //试算结售汇报送
        if (hasService(CommonContants.BOPSET_JSH_SERVICE)) {
            stopWatch.start("计算结售汇申报信息");
            logger.info("{} Serivce 计算结售汇申报信息", transName);
            JshmodRequest<BizInfoVo> jshmodRequest = BaseComponentBuilder.buildJshmodRequest(bizInfoVo, transactionServiceSet.getPtsList(), transactionServiceSet.getCbsMap(), transactionServiceSet.getSetmodVo(), transactionVo);
            jshmodRequest.reset();
            transactionServiceSet.setJshmodRequest(jshmodRequest);
            BopContext.load(jshmodRequest);
            jshmodService.calcJshmod(jshmodRequest.getJshmod());
            BopContext.remove();
            transactionVo.setJshmod(jshmodRequest.getJshmod());
            stopWatch.stop();
        }

        //增加资本项目报送remapping
        if (hasService(CommonContants.BOPSET_CFA_SERVICE)) {

            String transname = NULLSTR;
            String recFingua = NULLSTR;
            Cfagit cfagitRequestVo = transactionVo.getCfagit();
            transname = transactionVo.getTransName();
            if (!MdaUtils.isEmpty(cfagitRequestVo)) {
                recFingua = (String) cfagitService.cfaGetGIDataByTrans(transName, bizInfoVo).get("recFingua");
            }
            if (!MdaUtils.isEmpty(cfagitRequestVo) && recFingua.equals("Y") && !(MdaUtils.isEmpty(cfagitRequestVo.getCfaflg()) || cfagitRequestVo.getCfaflg().equals("4"))) {
                stopWatch.start("计算资本项目申报信息");
                logger.info("{} Serivce 计算资本项目申报信息", transName);
                Cfagit cfagitRemap = BaseComponentBuilder.buildCfagit(bizInfoVo, bizAmdInfoVo, transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList(), transactionVo);
                cfagitRemap = cfagitService.cfaMappingData(cfagitRemap);
                transactionServiceSet.setCfagit(cfagitRemap);
                transactionVo.setCfagit(cfagitRemap);
                stopWatch.stop();
            }
        }

        //二期单独新增 资本项目报送mapping  范围: 国内外汇贷款  海外代付 远期信用证
        if (hasService(CommonContants.BOPSET_CFABOP_SERVICE)) {

            Cfabop cfabop = BaseComponentBuilder.buildCfabop(bizInfoVo, bizAmdInfoVo, transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList(), transactionVo);
            stopWatch.start("计算资本项目申报信息");
            cfabopService.calCfaData(cfabop);
            stopWatch.stop();
        }


        // 增加收支申报境内外收入报送
        if (hasService(CommonContants.BOPSET_SZSB_BOPGAT_SERVICE)) {
            stopWatch.start("计算收支申报境内外收入信息");
            logger.info("{} Serivce 计算收支申报境内外收入信息", transName);
            Bopgat bopgat = BaseComponentBuilder.buildBopgat(buildBizInfo(transactionVo), bizAmdInfoVo, transactionServiceSet, transactionVo);
            String szflg = bopgat.getSzflg();
            String basflg = bopgat.getBasflg();
            if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                bopgat = bopgatService.mappingBopgatDataAAAAAA(bopgat);
                transactionServiceSet.setBopgat(bopgat);
                transactionVo.setBopgat(bopgat);
            }
            stopWatch.stop();
        }

        // 增加收支申报境内外汇款报送
        if (hasService(CommonContants.BOPSET_SZSB_BOPREM_SERVICE)) {
            stopWatch.start("计算收支申报境内外汇款信息");
            logger.info("{} Serivce 计算收支申报境内外汇款信息", transName);
            Boprem boprem = BaseComponentBuilder.buildBoprem(buildBizInfo(transactionVo), bizAmdInfoVo, transactionServiceSet, transactionVo);
            String szflg = boprem.getSzflg();
            String basflg = boprem.getBasflg();
            if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                boprem = bopremService.mappingBopremDataAAAAAA(boprem);
                transactionServiceSet.setBoprem(boprem);
                transactionVo.setBoprem(boprem);
            }
            stopWatch.stop();
        }

        // 增加收支申报境内外承兑报送
        if (hasService(CommonContants.BOPSET_SZSB_BOPPAY_SERVICE)) {
            stopWatch.start("计算收支申报境内外承兑信息");
            logger.info("{} Serivce 计算收支申报境内外承兑信息", transName);
            Boppay boppay = BaseComponentBuilder.buildBoppay(bizInfoVo, bizAmdInfoVo, transactionServiceSet, transactionVo);
            String szflg = boppay.getSzflg();
            String basflg = boppay.getBasflg();
            if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                boppay = boppayService.mappingBoppayDataAAAAAA(boppay);
                transactionServiceSet.setBoppay(boppay);
                transactionVo.setBoppay(boppay);
            }
            stopWatch.stop();
        }

        //将更新后的交易Vo存入transactionServiceSet里面，方便后面快照，暂存的存文件
        transactionServiceSet.setTransactionVo(transactionVo);
        logger.info("{} Service完成重计算数据", transName);
        logger.info(stopWatch.prettyPrint());
        //Mtabut.ruleSavN198()  检查用户机构信息,单证中心柜员不能经办业务
        /*
        Bch bch = SettleContext.getUserSession().getBch();
        if ("0".equals(bch.getLev())) {
            throw new CommonServiceException("单证中心柜员不能经办业务!!!");
        }
         */
    }

    public void initTrnInfo(T transactionVo) {
        if (needBimdata()) {
            //初始化BIMDATA数据
            trnmodService.initBimdata();
        }

        String transName = transactionVo.getTransName();
        logger.info("{} Service初始准备Trn相关信息", transName);

        TrnmodVo trnmod = transactionHelpService.getTransactionStoreSet().getTrnmodVo();
        //Setmod.ruleMtabutSavN220() 设置Trn重算标志
        if (!SettleContext.getTransName().contains("OPN") && !SettleContext.getTransName().contains("POP")) {
            Object rec = transactionHelpService.getTransactionStoreSet().getRec();
            trnmodService.troLockExistingContract(trnmod, rec);
        }
        if (hasService(CommonContants.SETMOD_SERVICE)) {
            logger.info("{} Service设置Trn重算标志", transName);
            SetmodVo setmod = transactionHelpService.getTransactionStoreSet().getSetmodVo();
            setmodService.setTrnXreFields(setmod, trnmod);
        }
        //Trnmod.ruleMtabutSavN490()
        if (!sysmodService.sptIsExeLoaded(trnmod.getSpt().getSta())) {
            trnmod.getTrn().setInr(counterService.dbCounterFormat("TRN"));
            logger.info("{} Service 此次保存的Trn Inr:{}", transName, trnmod.getTrn().getInr());
            TrnInfo trnInfo = transactionVo.getTrnInfo();
            if (trnInfo != null) {
                trnmod.getTrn().setImginr(trnInfo.getImginr());
            }
        }
        Object rec = transactionHelpService.getTransactionStoreSet().getRec();
        Bch bch = SettleContext.getUserSession().getBch();
        Bch wrkbch = SettleContext.getUserSession().getWrkbch();
        //Mtabut.ruleSavN450()  设置业务表的机构信息
        sysmodService.setRecBchInfo(rec, bch, wrkbch);
        logger.info("{} Service 设置业务表的机构信息:bchKeyinr:{},branchInr:{}",
                Optional.ofNullable(bch).map(bh -> bh.getInr()).orElse(""),
                Optional.ofNullable(wrkbch).map(wh -> wh.getInr()).orElse(""));

        //保存TRNDATA数据，用于业务交易回退
        //logger.info("{} Service 存储trndata成功Trn Inr:{}", transName, trnmod.getTrn().getInr());
        //trnmodService.storeTrndata(trnmod, transactionVo);
    }

    public void storeTrndata(T transactionVo) {
        BizInfoVo bizInfoVo = buildBizInfo(transactionVo);
        if (bizInfoVo != null) {
            String objtyp = bizInfoVo.getObjtyp();
            String objinr = Utils.getFieldValue(transactionVo, objtyp.toLowerCase() + "grp//rec//inr", "");
            if (StringUtils.isEmpty(objinr)) {
                String inr = Utils.getFieldValue(transactionHelpService.getTransactionStoreSet().getRec(), "inr", "");
                if (StringUtils.isNotEmpty(inr)) {
                    Utils.setFieldValue(Utils.getFieldValue(transactionVo, objtyp.toLowerCase() + "grp//rec"), "inr", inr);
                }
            }
        }
        //pte inr赋值
        if (hasService(CommonContants.LIAALL_SERVICE) && !sysmodService.isSdhBusiness() && needStoreLiaall()) {
            LiaallVo afterSaveLiaallVo = transactionHelpService.getTransactionStoreSet().getLiaall();
            List<LiaallgVo> liaallgs = transactionVo.getLiaallg();
            if (liaallgs != null && liaallgs.size() > 0) {
                for (int i=0; i<liaallgs.size(); i++) {
                    if (StringUtils.isEmpty(liaallgs.get(i).getPtegrp().getRec().getInr())) {
                        liaallgs.get(i).getPtegrp().getRec().setInr(afterSaveLiaallVo.getLiaallg().get(i).getPtegrp().getRec().getInr());
                    }
                }
            }
        }
        String transName = transactionVo.getTransName();
        TrnmodVo trnmod = transactionHelpService.getTransactionStoreSet().getTrnmodVo();
        //保存TRNDATA数据，用于业务交易回退
        logger.info("{} Service 存储trndata成功Trn Inr:{}", transName, trnmod.getTrn().getInr());
        trnmodService.storeTrndata(trnmod, transactionVo);
    }

    /**
     * 自身交易的存盘
     */
    protected abstract void txnSave(T transactionVo);

    /**
     * 自身交易的存盘
     */
    protected abstract Map<String, String> txnCheck(T transactionVo);

    /**
     * 为公共组件创建BizInfoVo
     */
    protected abstract BizInfoVo buildBizInfo(T transactionVo);

    /**
     * 为公共组件创建BizAmdInfoVo
     */
    protected BizAmdInfoVo buildBizAmdInfo(T transactionVo) {
        return null;
    }

    /**
     * 公共模块的存盘
     */
    public void saveCommonComponents(T transactionVo) {
        String transName = transactionVo.getTransName();
        logger.info("{} Service开始保存公共模型数据", transName);
        StopWatch stopWatch = new StopWatch(transName.toUpperCase() + "Service 公共模型数据保存分析");
        TransactionServiceSet transactionServiceSet = transactionHelpService.getTransactionStoreSet();
        TrnmodVo trnmod = transactionHelpService.getTransactionStoreSet().getTrnmodVo();
        trnmodService.ordLockForTRN(trnmod);
        if (hasService(CommonContants.LIACCV_SERVICE) && !sysmodService.isSdhBusiness()) {
            stopWatch.start("保证金liaccv");
            logger.info("{} Service开始保存保证金liaccv模型数据", transName);
            LiaccvVo liaccvVo = transactionServiceSet.getLiaccvVo();
            liaccvService.storeCCV(liaccvVo);
            stopWatch.stop();
        }
        if (hasService(CommonContants.LIAALL_SERVICE) && !sysmodService.isSdhBusiness() && needStoreLiaall()) {
            stopWatch.start("表外liaall");
            logger.info("{} Service开始保存表外liaall模型数据", transName);
            LiaallVo liaallVo = transactionServiceSet.getLiaall();
            liaallService.storeAll(liaallVo);
            stopWatch.stop();
        }
        if (hasService(CommonContants.LIMMOD_SERVICE)) {
            stopWatch.start("额度limmod");
            logger.info("{} Service开始保存额度limmod模型数据", transName);
            LimmodVo limmodVo = transactionServiceSet.getLimmodVo();
            TrnmodVo trnmodVo = transactionServiceSet.getTrnmodVo();
            limmodVo.setTrninr(trnmod.getTrn().getInr());
            limmodVo.getRec().setObjinr(trnmod.getTrn().getObjinr());
            limoccservice.LimRegParstm(limmodVo);
            stopWatch.stop();
        }
        if (hasService(CommonContants.SETMOD_SERVICE) && !sysmodService.isSdhBusiness()) {
            //Setmod.ruleMtabutSavN1205() 根据setmod的setfeg数据存盘fep数据
            stopWatch.start("费用账务Setmod");
            logger.info("{} Service开始保存费用账务Setmod模型数据", transName);
            SetmodVo setmodVo = transactionServiceSet.getSetmodVo();
            updateBizInfoVo(setmodVo.getRec(), transactionVo);
            setmodService.saveSetmod(setmodVo);
            stopWatch.stop();
        }
        if (hasService(CommonContants.GLEMOD_SERVICE)) {
            //Glemod.ruleMtabutSavN1200()  存盘gle分录
            stopWatch.start("分录Glemod");
            logger.info("{} Service开始保存分录Glemod模型数据", transName);
            GlemodVo glemodVo = transactionServiceSet.getGlemodVo();
            updateBizInfoVo(glemodVo.getRec(), transactionVo);
            if (hasService(CommonContants.LIAALL_SERVICE)) {
                LiaallVo liaallVo = transactionServiceSet.getLiaall();
                glemodVo.setLiaallg(liaallVo.getLiaallg());
            }
            if (hasService(CommonContants.SETMOD_SERVICE)) {
                SetmodVo setmodVo = transactionServiceSet.getSetmodVo();
                glemodVo.setSetfog(setmodVo.getSetfog());
                glemodVo.setSetfeg(setmodVo.getSetfeg());
                glemodVo.setSetglg(setmodVo.getSetglg());
                glemodVo.setRec(setmodVo.getRec());
            }
            if (!sysmodService.isSdhBusiness()) {
                //普通经办交易存入gle数据
                glemodService.saveGle(glemodVo);
            } else {
                //登记交易存入交易文件中(试算不存盘)
                glemodService.fillGLEStream(glemodVo);
            }
            transactionVo.setGles(glemodVo.getGles());
            stopWatch.stop();
        }
        //Mtabut.ruleSavN3000()
        if (hasService(CommonContants.TRNDOC_SERVICE)) {
            stopWatch.start("报文面函Trndoc");
            logger.info("{} Service开始保存报文面函Trndoc模型数据", transName);
            //设置transactionVo到内存里面，方便后面生成报文面函
            transactionServiceSet.setTransactionVo(MdaUtils.deepClone(transactionVo));
            TrndocVo trndocVo = transactionServiceSet.getTrndocVo();
            trndocService.saveDocuments(trndocVo);
            stopWatch.stop();
        }
        //Mtabut.ruleSavN3000()
        if (hasService(CommonContants.TRNDIA_SERVICE)) {
            stopWatch.start("记事簿Diary Trndia");
            logger.info("{} Service开始保存记事簿Diary Trndia模型数据", transName);
            TrndiaVo trndiaVo = transactionServiceSet.getTrndiaVo();
            if (!sysmodService.isSdhBusiness()) {//普通经办交易存入dia数据
                updateBizInfoVo(trndiaVo.getRec(), transactionVo);
                trndiaService.saveNewDiaries(trndiaVo);
            }
            stopWatch.stop();
        }
        //Mtabut.ruleSavN3000()

        if (hasService(CommonContants.BOPSET_RMB_SERVICE)) {
            stopWatch.start("人民币报送");
            logger.info("{} Service开始保存人民币报送模型数据", transName);
            RmbbopRequest<BizInfoVo, BizAmdInfoVo> rmbbopRequest = transactionServiceSet.getRmbbopRequest();
            //普通经办交易存入rmbbop数据
            if (!sysmodService.isSdhBusiness()) {
                BopContext.load(rmbbopRequest);
                rmbbopService.saveRmbbop(rmbbopRequest.getRmbbop());
                BopContext.remove();
            }
            stopWatch.stop();
        }

        // 结售汇报送
        if (hasService(CommonContants.BOPSET_JSH_SERVICE)) {
            stopWatch.start("结售汇报送");
            logger.info("{} Service开始保存结售汇报送模型数据", transName);
            JshmodRequest<BizInfoVo> jshmodRequest = transactionServiceSet.getJshmodRequest();
            BopContext.load(jshmodRequest);
            jshmodService.saveJshmod(jshmodRequest.getJshmod());
            BopContext.remove();
            stopWatch.stop();
        }

        //资本项目报送
        if (hasService(CommonContants.BOPSET_CFA_SERVICE)) {
            stopWatch.start("资本项目报送");
            logger.info("{} Service开始保存资本项目报送模型数据", transName);
            String transname = NULLSTR;
            String recFingua = NULLSTR;
            Cfagit cfagitRequestVo = transactionServiceSet.getCfagit();
            transname = transactionServiceSet.getTransactionVo().getTransName();
            if (!MdaUtils.isEmpty(cfagitRequestVo)) {
                recFingua = (String) cfagitService.cfaGetGIDataByTrans(transName, cfagitRequestVo.getRec()).get("recFingua");
            }
            if (!MdaUtils.isEmpty(cfagitRequestVo) && recFingua.equals("Y") && !(MdaUtils.isEmpty(cfagitRequestVo.getCfaflg()) || cfagitRequestVo.getCfaflg().equals("4"))) {
                if (!sysmodService.isSdhBusiness()) {//普通经办交易存入dia数据
                    cfagitService.setCfaType("EBA");//EBA对外担保
                    cfagitService.cfaBopSaveData(cfagitRequestVo);
                }
            }
            stopWatch.stop();
        }

        //二期 资本项目报送保存
        if (hasService(CommonContants.BOPSET_CFABOP_SERVICE)) {
            stopWatch.start("资本项目报送");
            logger.info("{} Service开始保存资本项目报送模型数据", transName);
            Cfabop cfabop = transactionServiceSet.getTransactionVo().getCfabop();
            if (!sysmodService.isSdhBusiness()) {
                //收单行报送数据不能存表
                cfabopService.saveCfaData(cfabop);
            }
            stopWatch.stop();
        }


        // 收支申报境内外收入报送存盘
        if (hasService(CommonContants.BOPSET_SZSB_BOPGAT_SERVICE)) {
            stopWatch.start("收支申报境内外收入报送");
            logger.info("{} Service开始保存收支申报境内外收入模型数据", transName);
            Bopgat bopgat = transactionServiceSet.getBopgat();
            if (!MdaUtils.isEmpty(bopgat)) {
                String szflg = bopgat.getSzflg();
                String basflg = bopgat.getBasflg();
                String aloneflg = bopgat.getAloneflg();
                String enableflg = bopgat.getEnableflg();
                if (!sysmodService.isSdhBusiness()) {//普通经办交易存入dia数据
                    if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                        bopgatService.saveBopgatData(bopgat);
                        //不随业务申报 需要生成 spt  和 bak 后续到修改交易补录申报 管理信息
                        //试点行才进行待办生成 -- 不生成待办改为更新补录状态
//                        if ("2".equals(aloneflg) && "Y".equals(enableflg)) {
//                            logger.info("{} Service不随业务申报生成收支申报境内外收入待办数据", transName);
//                            bopgatService.saveSpt(bopgat);
//                        }
                    }
                }
            }
            stopWatch.stop();
        }

        // 收支申报境内外汇款报送存盘
        if (hasService(CommonContants.BOPSET_SZSB_BOPREM_SERVICE)) {
            stopWatch.start("收支申报境内外汇款报送");
            logger.info("{} Service开始保存收支申报境内外汇款模型数据", transName);
            Boprem boprem = transactionServiceSet.getBoprem();
            if (!MdaUtils.isEmpty(boprem)) {
                String szflg = boprem.getSzflg();
                String basflg = boprem.getBasflg();
                String aloneflg = boprem.getAloneflg();
                String enableflg = boprem.getEnableflg();
                if (!sysmodService.isSdhBusiness()) {//普通经办交易存入dia数据
                    if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                        if (!MdaUtils.isEmpty(boprem)) {
                            bopremService.saveBopremData(boprem);
                            //不随业务申报 需要生成 spt  和 bak 后续到修改交易补录申报 管理信息
                            //试点行才进行待办生成
//                            if ("2".equals(aloneflg) && "Y".equals(enableflg)) {
//                                logger.info("{} Service不随业务申报生成收支申报境内外汇款待办数据", transName);
//                                bopremService.saveSpt(boprem);
//                            }
                        }
                    }
                }
            }
            stopWatch.stop();
        }

        // 收支申报境内外承兑报送存盘
        if (hasService(CommonContants.BOPSET_SZSB_BOPPAY_SERVICE)) {
            stopWatch.start("收支申报境内外承兑报送");
            logger.info("{} Service开始保存收支申报境内外承兑模型数据", transName);
            Boppay boppay = transactionServiceSet.getBoppay();
            if (!MdaUtils.isEmpty(boppay)) {
                String szflg = boppay.getSzflg();
                String basflg = boppay.getBasflg();
                String aloneflg = boppay.getAloneflg();
                String enableflg = boppay.getEnableflg();
                if (!sysmodService.isSdhBusiness()) {//普通经办交易存入dia数据
                    if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                        if (!MdaUtils.isEmpty(boppay)) {
                            boppayService.saveBoppayData(boppay);
                            //不随业务申报 需要生成 spt  和 bak 后续到修改交易补录申报 管理信息
                            //试点行才进行待办生成
//                            if ("2".equals(aloneflg) && "Y".equals(enableflg)) {
//                                logger.info("{} Service不随业务申报生成收支申报境内外付款承兑待办数据", transName);
//                                boppayService.saveSpt(boppay);
//                            }
                        }
                    }
                }
            }
            stopWatch.stop();
        }

        stopWatch.start("工作流Trnmod");
        if (transactionVo.getTrnInfo() != null) {
            trnmod.getOrdmod().setOreList(transactionVo.getTrnInfo().getOreList());
        }
        saveTrnmodInfo(trnmod);
        if (StringUtils.isEmpty(transactionVo.getTrninr()) && trnmod.getTrn() != null) {
            transactionVo.setTrninr(trnmod.getTrn().getInr());
        }
        stopWatch.stop();
        saveBatchData(trnmod);//保存cecm数据

        //收单行上收逻辑处理 生成上收业务的  spt 和 que  通过 Hldflg字段进行判断。Hldflg=‘R’为锁住业务
        if (sysmodService.isSdhBusiness()) {
            stopWatch.start("收单行特殊处理");
            logger.info("{} Service开始保存收单行相关数据", transName);
            // Bch upperbch=sysmodService.getUpperBch(null);
            Bch upperbch = bchService.getByBranch("1000");
            Bch wrkBch = SettleContext.getUserSession().getWrkbch();
            Spt spt = new Spt();
            spt.setHldflg("Y");//收单行上收spt标记
            spt.setBchkeyinr(upperbch.getInr());
            spt.setBranchinr(wrkBch != null ? wrkBch.getInr() : upperbch.getInr());
            spt.setRelcur(trnmod.getTrn().getReloricur());
            spt.setRelamt(trnmod.getTrn().getReloriamt());
            spt.setCreobjtyp("TRN");
            spt.setUsr(SettleContext.getUserSession().getUsr().getExtkey());
            spt.setCreobjinr(trnmod.getTrn().getInr());
            spt.setOrdinr(trnmod.getTrn().getOrdinr());
            spt.setFrm(sysmodService.getNextFrame(SettleContext.getTransName()));
            Object rec = transactionHelpService.getTransactionStoreSet().getRec();
            String objName = Utils.getFieldValue(rec, "nam");
            if (StringUtils.isEmpty(objName)) {
                objName = sysmodService.internalSetObjNam(rec, null);
            }
            TrnInfo trnInfo = transactionVo.getTrnInfo();
            if (trnInfo != null) {
                spt.setImginr(trnInfo.getImginr());
            }
            sysmodService.sptSaveEntry(spt, rec, SptWaitingRegistration, transactionVo, objName);
            Spt incSpt = trnmod.getSpt();
            String channel = sysmodService.getChannelFromSta(incSpt.getSta());
            if (StringUtils.isEmpty(channel) && incSpt.getTxt() != null && incSpt.getTxt().length() == 3) {
                channel = incSpt.getTxt();
            }
            if (StringUtils.isEmpty(channel)) {
                channel = incSpt.getChannel();
            }
            if (StringUtils.isEmpty(channel) && incSpt != null && !StringUtils.isEmpty(incSpt.getInr())) {
                Que que = queMapper.selectByObjtypAndObjinr("SPT", incSpt.getInr());
                if (que != null) {
                    channel = que.getChannel();
                }
            }
            if (incSpt != null && "-INC-EJS-YPT-SWT-".indexOf(channel) > 0) {
                spt.setSta(incSpt.getSta());
                spt.setSmhinr(incSpt.getSmhinr());
                spt.setMsgtyp(incSpt.getMsgtyp());
                if (StringUtils.isEmpty(spt.getTxt())) {
                    spt.setTxt(channel);
                }
                spt.setChannel(channel);
                sysmodService.sdbUpdate(spt);
                Que que = queMapper.selectByObjtypAndObjinr("SPT", spt.getInr());
                que.setChannel(channel);
                que.setMsgtyp(incSpt.getMsgtyp());
                sysmodService.sdbUpdate(que);
            }
            stopWatch.stop();
        }


        stopWatch.start("快照");
        //save按钮保存交易快照.dsp文件
        logger.info("{} Service保存快照,inr:{}", transName, trnmod.getTrn().getOrdinr());
        sysmodService.streamSaveInSubDir(transactionVo, "display", trnmod.getTrn().getInr() + ".dsp");
        stopWatch.stop();
        stopWatch.start("队列管理器处理");
        quemodService.sptQueUpdateStatus(transactionVo.getSpt(), CommonContants.QUE_STATUS_DELETED);//更新spt为删除状态

        if (StringUtils.isNotEmpty(transactionVo.getSpt().getInr()) && !Objects.equals(transactionVo.getSpt().getSta(), "PEN")) {
            String usr = SettleContext.getUserSession().getUsr().getExtkey();
            taskDistService.commitTask(usr);//重新计算阈值
            logger.info("{} 业务提交重新计算阈值,{}", transName, trnmod.getTrn().getOwnref());
        }
        stopWatch.stop();
        logger.info("{} Service完成保存公共模型数据", transName);
        logger.info(stopWatch.prettyPrint());
    }

    /**
     * 公共模块检核
     */
    public Map<String, String> checkCommonComponents(T transactionVo) {
        logger.info("执行交易公共模块交易");
        Map<String, String> maps = new HashMap<>();
        TransactionServiceSet transactionServiceSet = transactionHelpService.getTransactionStoreSet();
        if (hasService(CommonContants.LIAALL_SERVICE)) {
            LiaallVo liaallVo = transactionServiceSet.getLiaall();
            maps.putAll(liaallValidator.validate(liaallVo));
        }
        if (hasService(CommonContants.LGBDET_SERVICE)) {
            LgbdetVo lgbdet = transactionServiceSet.getLgbdetVo();
            maps.putAll(lgbdetValidator.validate(lgbdet));
        }
        if (hasService(CommonContants.LIACCV_SERVICE)) {
            LiaccvVo liaccvVo = transactionServiceSet.getLiaccvVo();
            maps.putAll(liaccvValidator.validate(liaccvVo));
        }
        if (hasService(CommonContants.LIMMOD_SERVICE)) {
            LimmodVo limmodVo = transactionServiceSet.getLimmodVo();
            maps.putAll(limmodVo.getErrorVo().getRulemap());
            maps.putAll(limmodValidator.validate(limmodVo));
        }
        if (hasService(CommonContants.YPNMOD_SERVICE)) {
            YpnmodVo ypnmodVo = transactionServiceSet.getYpnmodVo();
            maps.putAll(ypnmodVo.getErrorVo().getRulemap());
        }
        if (hasService(CommonContants.SETMOD_SERVICE)) {
            SetmodVo setmodVo = transactionServiceSet.getSetmodVo();
            maps.putAll(setmodValidator.validate(setmodVo));
        }
        if (hasService(CommonContants.GLEMOD_SERVICE)) {
            GlemodVo glemodVo = transactionServiceSet.getGlemodVo();
            maps.putAll(glemodValidator.validate(glemodVo));
        }
        if (hasService(CommonContants.TRNDOC_SERVICE)) {
            TrndocVo trndocVo = transactionServiceSet.getTrndocVo();
            maps.putAll(trndocValidator.validate(trndocVo));
        }
        if (hasService(CommonContants.FANXIQIAN_SERVICE)) {
            MonmodVo monmodVo = transactionServiceSet.getMonmodVo();
//            monmodVo.setPtyinr(getPtyinr(transactionVo));
//            monmodVo.setDowngradeMsg(downgradeMsg(transactionVo));
            maps.putAll(monmodValidator.validate(monmodVo));

        }
        if (hasService(CommonContants.TRNDIA_SERVICE)) {
            TrndiaVo trndiaVo = transactionServiceSet.getTrndiaVo();
            maps.putAll(trndiaValidator.validate(trndiaVo));
        }

        if (hasService(CommonContants.BOPSET_RMB_SERVICE)) {
            RmbbopRequest<BizInfoVo, BizAmdInfoVo> rmbbopRequest = transactionServiceSet.getRmbbopRequest();
            if (!"2".equals(rmbbopRequest.getRmbbop().getAloneflg())) {
                BopContext.load(rmbbopRequest);
                maps.putAll(rmbbopValidator.validate(rmbbopRequest));
                BopContext.remove();
            }
        }
        if (hasService(CommonContants.BOPSET_JSH_SERVICE)) {
            JshmodRequest jshmodRequest = transactionServiceSet.getJshmodRequest();
            maps.putAll(jshmodValidator.validate(jshmodRequest));
        }
        if (hasService(CommonContants.BOPSET_CFA_SERVICE)) {
            //CFA报送
            String transname = NULLSTR;
            String recFingua = NULLSTR;
            Cfagit cfagitRequestVo = transactionServiceSet.getCfagit();
            transname = transactionServiceSet.getTransactionVo().getTransName();
            if (!MdaUtils.isEmpty(cfagitRequestVo)) {
                recFingua = (String) cfagitService.cfaGetGIDataByTrans(transname, cfagitRequestVo.getRec()).get("recFingua");
            }
            if (!MdaUtils.isEmpty(cfagitRequestVo) && recFingua.equals("Y") && !(MdaUtils.isEmpty(cfagitRequestVo.getCfaflg()) || cfagitRequestVo.getCfaflg().equals("4"))) {
                maps.putAll(cfabopValidator.validate(cfagitRequestVo));
            }
        }

        //二期 资本项目报送
        if (hasService(CommonContants.BOPSET_CFABOP_SERVICE)) {
            Cfabop cfabop = transactionServiceSet.getTransactionVo().getCfabop();
            maps.putAll(cfaValidator.validate(cfabop));
        }
        // 收支申报境内外收入
        if (hasService(CommonContants.BOPSET_SZSB_BOPGAT_SERVICE)) {
            Bopgat bopgat = transactionServiceSet.getBopgat();
            if (!MdaUtils.isEmpty(bopgat)) {
                String szflg = bopgat.getSzflg();
                String basflg = bopgat.getBasflg();
                if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                    maps.putAll(bopgatValidator.validate(bopgat.getCheckItems()));
                }
            }
        }
        // 收支申报境内外汇款
        if (hasService(CommonContants.BOPSET_SZSB_BOPREM_SERVICE)) {
            Boprem boprem = transactionServiceSet.getBoprem();
            if (!MdaUtils.isEmpty(boprem)) {
                String szflg = boprem.getSzflg();
                String basflg = boprem.getBasflg();
                if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                    maps.putAll(bopremValidator.validate(boprem.getCheckItems()));
                }
            }
        }

        // 收支申报境内外承兑
        if (hasService(CommonContants.BOPSET_SZSB_BOPPAY_SERVICE)) {
            Boppay boppay = transactionServiceSet.getBoppay();
            if (!MdaUtils.isEmpty(boppay)) {
                String szflg = boppay.getSzflg();
                String basflg = boppay.getBasflg();
                if (("1".equals(szflg) || "2".equals(szflg)) && "X".equals(basflg)) {
                    maps.putAll(boppayValidator.validate(boppay.getCheckItems()));
                }
            }
        }

        if (hasService(CommonContants.UMDMOD_SERVICE)) {
            UmdmodVo umdmodVo = new UmdmodVo();
            umdmodVo.setRec(buildBizInfo(transactionVo));
            DtoMapper.INSTANCE.updateVoToBo(transactionVo.getUmdmod(), umdmodVo);
            maps.putAll(umdmodValidator.validate(umdmodVo));
        }
        return maps;
    }

    /**
     * 存盘过程中检核交易 包含常规检核和warning提示
     *
     * @param transactionVo
     * @return
     */
    public boolean saveWithCheck(T transactionVo) {
        boolean checkFlag = true;
        Map<String, Object> errorMaps = new HashedMap();
        //1.后端@check检核
        Map<String, Object> ruleMaps = new HashedMap();
        ruleMaps.putAll(txnCheck(transactionVo));
        ruleMaps.putAll(checkCommonComponents(transactionVo));
        LimmodVo limmodVo = transactionHelpService.getTransactionStoreSet().getLimmodVo();
        if (!ObjectUtil.isEmpty(limmodVo)) {
            ruleMaps.putAll(limmodVo.getErrorVo().getRulemap());
        }
        logger.info("业务检核错误信息： {}", Utils.toPrettyJson(ruleMaps));
        errorMaps.put(CommonContants.CHECK_RULE_KEY, ruleMaps);
        //2.消息提示
        List<Map<String, Object>> maps = this.txnErrCheck(transactionVo);
//        //oit的消息提示
//        List<Map<String, Object>> oiterrormaps = oitenTryService.collectEntitiesAndNotice(transactionVo);
//        maps.addAll(oiterrormaps);
        if (!ObjectUtil.isEmpty(limmodVo)) {
            maps.addAll(limmodVo.getErrorVo().getErrorlist());
        }
        errorMaps.put(CommonContants.CHECK_ERROR_KEY, maps);
        //3.warning
        boolean checkWarningBalance = this.warning(transactionVo);
        if (!checkWarningBalance) {
            checkFlag = false;
            errorMaps.put(CommonContants.CHECK_WARNING_CHANGE, "Y");
        }
        //4.判断是否检核成功
        if (ruleMaps.size() > 0 || maps.size() > 0) {
            checkFlag = false;
        }
        transactionVo.setErrorMap(errorMaps);
        transactionVo.setWarnList(warnService.getTotalWarns());
        return checkFlag;
    }

    /**
     * 获取本行客户（校验DU01、OC51、OC52）
     * @return
     */
    protected String getPtyinr(T transactionVo){
        return null;
    }

    /**
     * 降级处理信息（OC52）
     * @return
     */
    protected String downgradeMsg(T transactionVo){
        return null;
    }
    /**
     * 更新业务主表BizInfo信息
     */
    protected void updateBizInfoVo(BizInfoVo bizInfoVo, T transactionVo) {
    }

    /**
     * 存盘trn,wfe,wfs,dia,ord,que等信息
     * source:mtabut.0007.script
     *
     * @param trnmod
     * @Rule(target="sav",order=3000) ruleSavN3000
     */
    public void saveTrnmodInfo(TrnmodVo trnmod) {
        //! save of transaction data and sequential files
        //! divided in
        //! phase 1 (starts with MTABUT\\SAV oder 500): get transaction INR, write and update in database, write BIMDATA, mark transaction as `entered`
        //! phase 2: write sequential files of transaction
        //! phase 3: mark transaction as complete, free all locks, commit transaction
        /*String cmd = NULLSTR;
        if( ctx.getErrorCode() == 0 )
        {
            cmd = "LimSav3000(\"" + trninr + "\")";
            Modules.invokeExpress(this,cmd,-1);
            if( ctx.getErrorCode() != 130 )
            {
                ctx.reraise();
            }
        }*/
        // Set Service for Execution Date
        //trnmod中trn ordinr提前获取值
        Ord ord = trnmod.getOrdmod().getOrd();
        if (ord != null) {
            trnmod.getTrn().setOrdinr(ord.getInr());
        }
        if (!MdaUtils.isEmpty(trnmod.getTrn().getExedat())) {
            trnismService.wfmAdd_EXEDAT(trnmod);
        }
        // send message status 空实现
        /*if( ! MdaUtils.isEmpty(ctx.absGet(Trnmod.class).getSmh().getInr()) && ! MdaUtils.isEmpty(ctx.absGet(Sysmod.class).getSpt().getInr()) )
        {
            if( MdaUtils.compareTo(ctx.absGet(Trnmod.class).getSmh().getInr(),ctx.absGet(Sysmod.class).getSpt().getSmhinr()) == 0 && MdaUtils.compareTo(ctx.absGet(Sysmod.class).getSpt().getSta(),"INC") == 0 )
            {
                ctx.absGet(Trnmod.class).getDocimm().sendMessageStatus ( ctx.absGet(Trnmod.class).getSmh(), "V" );
            }
        }*/
        //TODO this.getConinf().savOit();
        // set \\SYSMOD\\OBJNAM by posting xxTMOD.SetObjNam
        //internalSetObjNam(); 在其他地方已经实现了
        // set release method
        trnmodService.setWfsRelease(trnmod);
        if (!sysmodService.sptIsExeLoaded(trnmod.getSpt().getSta())) {
            String transName = SettleContext.getTransName();
            logger.info("{} Service开始保存签名信息", transName);
            // transaction created, moved up else is signed before entered
            trnmodService.sigWrite("G", trnmod.getTrn(), "CRE");  // transaction created
            // Finally write workflow
            trnismService.setWorkFlow(trnmod);
            // and write transaction record. With DBInsert because counter already set
            trnMapper.insert(trnmod.getTrn());
        } else {
            // in recalculation old TRN is reused. Set transaction flag for "recalculation done"
            trnmod.getTrn().setXreflg("3");
            TrndocVo trndocVo = transactionHelpService.getTransactionStoreSet().getTrndocVo();
            if (trndocService.isConInPdxChanged(trndocVo)) {
                SettleExceptionUtils.sysDump("Recalculation is not possible as contract data has been changed");
            }
        }
        // phase 4：
        //额度占用接口调用
        //--limtest---
        /**
         if IsEmpty( $sdhflg ) then
         **/
        /*if( ctx.getErrorCode() == 0 ) 额度处理目前不实现
        {
            cmd = "DealCL43(\"" + trninr + "\",\"1\")";
            Modules.invokeExpress(this,cmd,-1);
            if( ctx.getErrorCode() != 130 )
            {
                ctx.reraise();
            }
        }*/
        /**
         endif
         **/
        trnmodService.setTrnTxt(trnmod);
        trnmodService.trnStoreFinal(trnmod);
        // 增加额度处理，由于需要先产生ORD记录，因此在此调用
        /*String ordInr = Datas.getContent(this,"\\TRNMOD\\ORDMOD\\ORD\\INR");
        if( ctx.getErrorCode() == 0 )
        {
            cmd = "LsnSav3000(\"" + ordInr + "\")";
            Modules.invokeExpress(this,cmd,-1);
            if( ctx.getErrorCode() != 130 )
            {
                ctx.reraise();
            }
        }*/
        //由于需要取ord，因此在这里saveLgbdet
        if (hasService(CommonContants.LGBDET_SERVICE)) {
            lgbdetService.saveLGBDET(transactionHelpService.getTransactionStoreSet().getLgbdetVo());
        }
        LiaccvVo liaccvVo = transactionHelpService.getTransactionStoreSet().getLiaccvVo();
        liaccvService.fcdSav3000(trnmod.getOrdmod().getOrd().getInr(), liaccvVo);
        //更新ERS数据
        updateIncErs(trnmod);
        // Store the OBJ and INR of the contract (necessary especially for new contracts)
        //this.getCfg().setConobjtyp( Platform.recGetObj(this.getRec()));
        //this.getCfg().setConobjinr( Platform.recGetInr(this.getRec()));
        // Show warning panel in display file
        //Dynamic.showWarningsinDisplayFile();
        //Systems.status(MdaUtils.getI18NString("mtabut","CT000017"),ctx.absGet(Sysmod.class).getObjnam());
        //Platform.recSaveData(ctx.getRoot());
        //saverecgrp(); 存储recgrp到Istream中
        //Systems.redisplay();
        if (sysmodService.sptIsAnyLoaded(trnmod.getSpt().getSta())) {
            if (!MdaUtils.isEmpty(trnmod.getSmh().getInr())) {
                trnmodService.smhUpdate(trnmod);
                //!Modified by XH
                //更新chlrpt表
                trnmodService.updateChlrpt(trnmod.getTrn(), trnmod.getSmh());
            }
            updateOriginalTRN(trnmod.getSpt());
            sysmodService.sweSaveEntry(trnmod.getTrn(), trnmod.getSpt(), "SAV", trnmod.getSpt().getInr(), "");
            sysmodService.sptDeleteEntry(trnmod.getSpt());
            sysmodService.msgSaveEntry(trnmod.getTrn(), trnmod.getSpt(), "SAV", trnmod.getSpt().getInr(), "");
            // SPTDeleteEntry keeps \\SYSMOD\\SPT\\INR set for later DBfree, but
            // DBFreeAll follows (before LnkReturnToCaller)
            // LnkReturnToCaller=> LnkReturnToCallerKeepSPT => LnkReturnToFirst => SPTClear will try to DBFree
            // => Dump if transaction was started with SPT from commandline
//            trnmod.getSpt().setInr(NULLSTR);
            // When multiple SPT are to be handled, delete the additional SPTs
            //mtaButSptDelete();  mtaButSptClear sptcheck才有值
        }
        trnmodService.troCommit(trnmod.getTrn(), trnmod.getTrorescon());
        //Dynamic.dbCommitStateCheck();  SYSMOD_COMMIT caches处理 这里应该不需要
        // end of phase 1, transaction is in status `entered` now
        //ctx.getDaoSession().dbCommit();
        //Dynamic.dbCommitStateSave();
        //--limtest---
        // phase 2:
        // to save changes during save processing (eg reference number) in display
        //Utils.streamSave(trnmod.getTrnbim(),appEnv.getFullName("DATA","TRNDATA\\" + trnmod.getTrn().getInr() + ".DAT"));
//        trnmodService.storeTrndata(trnmod);
//        Object  rec=transactionHelpService.getTransactionStoreSet().getRec();
//        sysmodService.streamSaveInDir(rec, "TRNDATA", trnmod.getTrn().getInr()  + ".DAT");
//        -----------------结束------------------------------------
//        Streams.streamSet(trnStm,"");
//        Systems.setContext("SAVEDATASKIPEMPTY",true);
//        Datas.saveData(ctx.getRoot(),trnStm);
//        Systems.setContext("SAVEDATASKIPEMPTY",false);
/*        IStream image = new StreamImpl();
        Systems.saveDisplayToStream(image);
        Platform.streamSaveInSubDir(image,"DISPLAY",ctx.absGet(Trnmod.class).getTrn().getInr() + ".DSP");*/
        // phase 3:
        // mark transaction as final
        mtaButSetRelSta(trnmod.getTrnism().getWfmmod(), trnmod.getTrn());
        trnMapper.updateByPrimaryKeySelective(trnmod.getTrn());
        // create QUE entries for release
        trnmodService.trnQUECreate(trnmod.getTrn(), trnmod.getOrdmod().getOrd(), SettleContext.getUserSession().getUsr().getExtkey(), "");
        if (trnmod.getSpt() != null && !StringUtils.isEmpty(trnmod.getSpt().getInr())) {
            Que que = queMapper.selectByObjtypAndObjinrAndStatus("TRN", trnmod.getTrn().getInr(), TaskStatus.WAITING.getValue());
            Que sptQue = queMapper.selectByObjtypAndObjinr("SPT", trnmod.getSpt().getInr());
            String channel = sysmodService.getChannelFromSta(trnmod.getSpt());
            if (sptQue != null) {
                if (StringUtils.isEmpty(channel)) {
                    channel = sptQue.getChannel();
                }
                que.setAuto(sptQue.getAuto());
            }
            que.setChannel(channel);
            que.setCortyp(trnmod.getSpt().getCortyp());
            que.setFrontchannel(trnmod.getSpt().getFrontchannel());
            que.setMsgtyp(trnmod.getSpt().getMsgtyp());
            sysmodService.sdbUpdate(que);
            //更新收单行分行流水
            if ("X".equals(trnmod.getOrdmod().getOrd().getSdhflg())) {
                Trn sdhtrn = trnMapper.getSdhTrnInfo(trnmod.getOrdmod().getOrd().getInr());
                if (sdhtrn != null) {
                    //更新收单行流水信息
//                    Trn sdhtrnnew = MdaUtils.deepClone(trnmod.getTrn());
                    sdhtrn.setRelflg(TrnRelflgStatus.HEAD_HANDLE.getValue());
                    sysmodService.sdbUpdate(sdhtrn);
                }
            }
        }
        //Dynamic.dbCommitStateCheck();
        // this is the final release of all locks after the save of transaction data ist complete
        //ctx.getDaoSession().dbFreeAll();
        //commitAndPrompt();
        //Platform.lnkReturnToCaller();
    }

    public void saveBatchData(TrnmodVo trnmod) {
        if (!sysmodService.isSdhBusiness()) {
            cecmBatchStoreExecuteServiceImpl.execute(trnmod);
            logger.info("执行批量数据入库成功{}!", trnmod.getTrn().getInr());
        }
    }

    /**
     * 设置trn的relflg 授权状态
     *
     * @param wfmmod
     * @param trn
     */
    public void mtaButSetRelSta(WfmmodVo wfmmod, Trn trn) {
        //! sets the transaction status from WFE entry for PDS
        Wfe wfe = wfeMapper.getWfeByWfsinrAndSrv(wfmmod.getWfs().getInr(), "PDS");
        // if no PDS-WFE written or PDS-WFE is pending, then set release status from required signatures
        if (wfe == null || !(MdaUtils.compareTo(wfmmod.getWrkwfe().getSta(), "D") == 0)) {
            // set status from `release required` flag
            if (MdaUtils.compareTo(trn.getRelres(), trn.getRelreq()) == 0) {
                trn.setRelflg("R");
            } else {
                trn.setRelflg("W");
                if (wfmmodService.getIdx(wfmmod, "REL") > 0) {
                    wfe = wfeMapper.getWfeByWfsinrAndSrv(wfmmod.getWfs().getInr(), "REL");
                    if (wfe != null && !(MdaUtils.compareTo(wfmmod.getWrkwfe().getSta(), "W") == 0 || MdaUtils.compareTo(wfmmod.getWrkwfe().getSta(), "O") == 0)) {
                        // if REL-WFE exists but will not be executed again,
                        // set release status according to required signatures
                        // i.e. do not block interactive control & releaserelease
                    } else {
                        trn.setRelflg("B"); // ´B´locked until set to ´W´aiting by SRVREL
                    }
                }
            }
        } else {
            // otherwise transaction is automatically released
            trn.setRelflg("R");
        }
    }

    /**
     * 退回trn数据可以重新提交
     * source:mtabut.0029.script
     *
     * @param spt
     */
    public void updateOriginalTRN(Spt spt) {
        // Set RELFLG of the transaction that was loaded via SPT to `Picked Up`
        if (!MdaUtils.isEmpty(spt.getInr()) && !sysmodService.sptIsExeLoaded(spt.getSta())) {
            if (MdaUtils.compareTo(spt.getObjtyp(), "TRN") == 0 && !MdaUtils.isEmpty(spt.getObjinr())) {
                logger.info("更新Spt关联的Trn，trnInr:{}", spt.getObjinr());
                Trn trn = new Trn();
                trn.setRelflg("P");
                trn.setInr(spt.getObjinr());
                trnMapper.updateByPrimaryKeySelective(trn);
            }
        }
    }

    /**
     * 交易是否需要bimdata参与回滚
     */
    protected boolean needBimdata() {
        return true;
    }

    /**
     * 交易是否需要表外存盘
     */
    protected boolean needStoreLiaall() {
        return true;
    }

    /**
     * 请各交易子类实现此方法，构建需要的组数
     *
     * @param bo
     * @param fieldMap
     * @return 返回需要额外添加的
     */
    public Map<String, Object> buildForTextData(T bo, Map<String, String> fieldMap) {
        String lowerTransName = bo.getTransName().toLowerCase();
        switch (lowerTransName) {
            case "nitopn":
            case "nitpop":
            case "hitopn":
            case "hitpop":
            case "gitopn":
            case "gitpop":
            case "nitmjm":
                IGidTextFormat gidTextFormat = (IGidTextFormat<T>) SpringUtils.getBean(lowerTransName + ".Format");
                return gidTextFormat.getFormatData(bo);
        }
        return null;
    }

    /**
     * 这个只是默认实现，还是需要交易自己来补充数据
     * 例如要塞adr、补充grp下的字段
     *
     * @param template
     * @param fieldMap
     * @param bo
     * @return
     */
    @Override
    public String convertText(String template, Map<String, String> fieldMap, T bo) {
        //加载SettleContext
        this.beforeSave(bo);
        Map<String, Object> extraMap = buildForTextData(bo, fieldMap);
        return ObjectUtils.exchangeTemplateVar(template, fieldMap, bo, extraMap);
    }

//    @Override
//    public String convertTextExceType(String template, Map<String, String> fieldMap, T bo) {
//        Map<String, Object> extraMap = buildForTextData(bo, fieldMap);
//        return ObjectUtils.exchangeTemplateVarExceType(template, fieldMap, bo, extraMap);
//    }

    @Override
    public boolean otherCheck(T transactionVo) {
        boolean checkFlag = true;
        TransactionServiceSet transactionServiceSet = transactionHelpService.getTransactionStoreSet();
        BizInfoVo bizInfoVo = buildBizInfo(transactionVo);
        BizAmdInfoVo bizAmdInfoVo = buildBizAmdInfo(transactionVo);
        /**
         * 筛查统一名单
         */
        if (hasService(CommonContants.UMDMOD_SERVICE)) {
            StopWatch stopWatch = new StopWatch(SettleContext.getTransName() + "统一名单计算分析");
            stopWatch.start("筛查统一名单");
            UmdmodVo umdmodVo = BaseComponentBuilder.buildUmdmodVo(bizInfoVo, bizAmdInfoVo, transactionServiceSet.getCbsMap(),
                    transactionServiceSet.getPtsList(), transactionServiceSet.getPtsaddg(), transactionVo);
            DtoMapper.INSTANCE.updateVoToBo(transactionVo.getUmdmod(), umdmodVo);
            umdmodVo.reset();
            umdmodService.assertUmdmod(umdmodVo);
            transactionServiceSet.setUmdmodVo(umdmodVo);
            DtoMapper.INSTANCE.updateBoToVo(umdmodVo, transactionVo.getUmdmod());
            if (umdmodVo.getErrormaps() != null && umdmodVo.getErrormaps().size() > 0) {
                checkFlag = false;
                Map<String, Object> errorMaps = new HashedMap();
                errorMaps.put(CommonContants.CHECK_ERROR_KEY, umdmodVo.getErrormaps());
                logger.info("统一名单检核错误信息： {}", umdmodVo.getErrormaps());
                transactionVo.setErrorMap(errorMaps);
            }
            stopWatch.stop();
        }
        return checkFlag;

    }

    /**
     * source:mtabut.0093.script
     */
    public void updateIncErs(TrnmodVo trnmod) {
        //!############################
        //!更新ERS数据
        //!暂时只对单证通系统做处理
        //!############################
        Smh smh = trnmod.getSmh();
        Trn trn = trnmod.getTrn();
        if (smh == null) return;
        // 针对递转报文来说,经办保存时更新ers表中trninr
        if(StringUtils.isNotEmpty(smh.getMsgtyp()) && Strings.pos("-D60-D61-DZKLSQ-DZXGSQ-", smh.getMsgtyp()) > 0){
            Ers ers = ersMapper.getErsBySmhinr(smh.getInr());
            ers.setOwnref(trn.getOwnref());
            ers.setInifrm(trn.getInifrm());
            ers.setIniusr(trn.getIniusr());
            ers.setUsrbchcod(SettleContext.getUserSession().getBch().getBranch());
            ers.setObjtyp(trn.getObjtyp());
            ers.setObjinr(trn.getObjinr());
            ers.setTrninr(trn.getInr());
            ers.setTxtinf(trn.getOwnref());
            ersMapper.updateByPrimaryKey(ers);
        }
        if (!MdaUtils.isEmpty(smh.getInr()) && Strings.pos("-ERX-GNZ-", smh.getCortyp()) > 0) {
            Ers ers = ersMapper.getErsBySmhinr(smh.getInr());
            if (ers != null && Strings.pos("-321-Z00238-", ers.getMsgfrm()) > 0) {
                ers.setOwnref(trn.getOwnref());
                ers.setInifrm(trn.getInifrm());
                ers.setIniusr(trn.getIniusr());
                ers.setUsrbchcod(SettleContext.getUserSession().getBch().getBranch());
                ers.setObjtyp(trn.getObjtyp());
                ers.setObjinr(trn.getObjinr());
                ers.setTrninr(trn.getInr());
                if (MdaUtils.compareTo(ers.getMsgfrm(), "321") == 0) {
                    Fujian fujian = fujianMapper.getFujianByFtynum(ers.getFtynum());
                    if (fujian != null) {
                        ers.setImgnum(fujian.getDocid());
                        fujian.setTrninr(trn.getInr());
                        fujianMapper.update(fujian);
                    }
                    if (!StringUtils.isEmpty(ers.getFtynum())) {
                        logger.info("321-Z00238影像业务流水号:{}", ers.getFtynum());
                        List<Img> imgList = imgMapper.getImgListByftynum(ers.getFtynum());
                        if (imgList != null) {
                            for (int i = 0; i < imgList.size(); i++) {
                                imgList.get(i).setTrninr(trn.getInr());
                                imgMapper.update(imgList.get(i));
                            }
                        }
                    }
                }
                ers.setTxtinf(trn.getOwnref());
                ersMapper.updateByPrimaryKey(ers);
            }
        }
        //-----YPTTEST-----
        if (!MdaUtils.isEmpty(smh.getInr()) && MdaUtils.compareTo(smh.getCortyp(), "YPT") == 0) {
            Ers ers = ersMapper.getErsBySmhinr(smh.getInr());
            if (ers != null && (MdaUtils.compareTo(ers.getMsgfrm(), "321") == 0 || MdaUtils.compareTo(ers.getMsgfrm(), "YPT") == 0)) {
                ers.setOwnref(trn.getOwnref());
                ers.setInifrm(trn.getInifrm());
                ers.setIniusr(trn.getIniusr());
                ers.setUsrbchcod(SettleContext.getUserSession().getBch().getBranch());
                ers.setObjtyp(trn.getObjtyp());
                ers.setObjinr(trn.getObjinr());
                ers.setTrninr(trn.getInr());
                Fujian fujian = fujianMapper.getFujianByFtynum(ers.getFtynum());
                if (fujian != null) {
                    ers.setImgnum(fujian.getDocid());
                    fujian.setTrninr(trn.getInr());
                    fujianMapper.update(fujian);
                }
                if (!StringUtils.isEmpty(ers.getFtynum())) {
                    logger.info("YPT 影像业务流水号:{}", ers.getFtynum());
                    List<Img> imgList = imgMapper.getImgListByftynum(ers.getFtynum());
                    if (imgList != null) {
                        for (int i = 0; i < imgList.size(); i++) {
                            imgList.get(i).setTrninr(trn.getInr());
                            imgMapper.update(imgList.get(i));
                        }
                    }
                }
                if (MdaUtils.compareTo(ers.getOthersno(), "E0000003") == 0 && MdaUtils.compareTo(ers.getMsgtyp(), "BHKLSQ") == 0) {
                    ers.setBussta("02");
                }
                // 保存来自云平台业务产生的业务编号
                ers.setTxtinf(trn.getOwnref());
                ersMapper.updateByPrimaryKey(ers);
            }
        }
        //------CIPS\SWIFT------
        String transName = SettleContext.getTransName();
        if (!MdaUtils.isEmpty(smh.getInr()) && (MdaUtils.compareTo(smh.getCortyp(), "LET") == 0 || MdaUtils.compareTo(smh.getCortyp(), "SWT") == 0) && StringUtils.isNotEmpty(transName) && "CPTADV".equalsIgnoreCase(transName)) {
            if (trnmod.getSpt() != null && StringUtils.isNotEmpty(trnmod.getSpt().getSta()) && Strings.pos("-CIU-CIV-CIW-COR-PEN-INC-", trnmod.getSpt().getSta()) > 0) {
                if(StringUtils.isNotEmpty(trnmod.getSpt().getSmhinr())){
                    Smh wrksmh = smhMapper.selectByGrpinrAndDirAndCortypAndMsgtyp(trnmod.getSpt().getSmhinr(),"<","T2D","ERX");
                    if(wrksmh != null){
                        String wrksmhinr = wrksmh.getInr();
                        if(StringUtils.isNotEmpty(wrksmhinr)){
                            Ers ers = ersMapper.getErsBySmhinr(wrksmhinr);
                            if(ers != null){
                                ers.setOwnref(trn.getOwnref());
                                ers.setInifrm(trn.getInifrm());
                                ers.setIniusr(trn.getIniusr());
                                ers.setUsrbchcod(SettleContext.getUserSession().getBch().getBranch());
                                ers.setObjtyp(trn.getObjtyp());
                                ers.setObjinr(trn.getObjinr());
                                ers.setTrninr(trn.getInr());
                                ers.setTxtinf(trn.getOwnref());
                                ersMapper.updateByPrimaryKey(ers);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 合并来报Spt数据到交易BO
     *
     * @param bo
     */
    protected void mergeSptDate(BaseTransactionVo bo) {
        if (sptDataComponent.needMergeSptData(bo)) {
            BaseTransactionVo sptBo = sysmodService.sptLoadData(bo.getClass(), bo.getSpt().getInr());
            sptDataComponent.mergeSptAndContractData(sptBo, bo);
        }
    }

    /**
     * 融资组件试算
     *
     * @param trtcre
     * @param transactionVo
     */
    protected void calcTrtcre(Trtcre trtcre, T transactionVo) {
        TransactionServiceSet transactionServiceSet = transactionHelpService.getTransactionStoreSet();
        BaseComponentBuilder.fillTrtcre(trtcre, buildBizInfo(transactionVo), transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList(), transactionVo.getLiaccvg());
        trtcreService.assertTrtcre(trtcre);
    }

    /**
     * 融资组件存盘
     *
     * @param trtcre
     * @param transactionVo
     */
    protected void saveTrtcre(Trtcre trtcre, T transactionVo) {
        if (!MdaUtils.isEmpty(trtcre.getCrefinflg()) && !sysmodService.isSdhBusiness()) {
            updateBizInfoVo(trtcre.getRec(), transactionVo);
            trtcreService.saveTrtcre(trtcre);
            SimpleModuleVo linkModule = SimpleModuleVo.buildModule(trtcre.getTrdgrp().getRec().getInr(), "TRD");
            //更新表外的objmodpath
            liaallService.updateLiaallgObjmodpath(transactionHelpService.getTransactionStoreSet().getLiaall().getLiaallg(), "FIN", linkModule);
            //更新备忘录的objmodpath
            trndiaService.updateDiaObjmodpath(transactionHelpService.getTransactionStoreSet().getTrndiaVo(), "", "TRTDUE", linkModule);
        }
    }

    /**
     * 委托方代付试算
     *
     * @param dftcre
     * @param transactionVo
     */
    protected void calcDftcre(Dftcre dftcre, T transactionVo) {
        TransactionServiceSet transactionServiceSet = transactionHelpService.getTransactionStoreSet();
        BaseComponentBuilder.fillDftcre(dftcre, buildBizInfo(transactionVo), transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList());
        dftcreService.assertDftcre(dftcre);
    }

    /**
     * 委托方代付存盘
     *
     * @param dftcre
     * @param transactionVo
     */
    protected void saveDftcre(Dftcre dftcre, T transactionVo) {
        if (!MdaUtils.isEmpty(dftcre.getDfflag()) && !sysmodService.isSdhBusiness()) {
            updateBizInfoVo(dftcre.getRec(), transactionVo);
            dftcreService.saveDftcre(dftcre);
            SimpleModuleVo linkModule = SimpleModuleVo.buildModule(dftcre.getDfdgrp().getRec().getInr(), "DFD");
            //更新表外的objmodpath
            liaallService.updateLiaallgObjmodpath(transactionHelpService.getTransactionStoreSet().getLiaall().getLiaallg(), "DFU", linkModule);
            //更新备忘录的objmodpath
            trndiaService.updateDiaObjmodpath(transactionHelpService.getTransactionStoreSet().getTrndiaVo(), "", "DFTDUE", linkModule);
            //更新费用的objmodpath
            setmodService.updateSetfelObjmod(transactionHelpService.getTransactionStoreSet().getSetmodVo().getSetfeg().getSetfel(), "DFFFEE", linkModule);
            setmodService.updateSetfelObjmod(transactionHelpService.getTransactionStoreSet().getSetmodVo().getSetfeg().getSetfel(), "PCINT", linkModule);
        }
    }

    /**
     * 表外试算
     *
     * @param transactionVo
     */
    protected void calcLiaall(T transactionVo) {
        TransactionServiceSet transactionServiceSet = transactionHelpService.getTransactionStoreSet();
        LiaallVo liaall = BaseComponentBuilder.buildLiaallVo(transactionVo.getLiaallg(), transactionVo.getLiaccvg(), buildBizInfo(transactionVo), buildBizAmdInfo(transactionVo), transactionServiceSet.getCbsMap(), transactionServiceSet.getPtsList());
        DtoMapper.INSTANCE.updateVoToBo(transactionVo.getLiaall(), liaall);
        liaall.reset();
        transactionServiceSet.setLiaall(liaall);
        liaallService.assertLIAALL(liaall);
        transactionVo.setLiaallg(liaall.getLiaallg());
        DtoMapper.INSTANCE.updateBoToVo(liaall, transactionVo.getLiaall());
    }

    /**
     * 试算融资还款组件
     *
     * @param bptbckVo
     * @param transactionVo
     */
    protected void calcBptbck(BptbckVo bptbckVo, T transactionVo) {
        bptbckVo.setRec(buildBizInfo(transactionVo));
        Utils.setFieldValue(bptbckVo.getRec(), "bptbckVo", null);
        bptbckService.assertBptbck(bptbckVo);
    }
}
