package pwc.taxtech.atms.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.nutz.lang.Files;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pwc.taxtech.atms.common.*;
import pwc.taxtech.atms.common.message.EnterpriseAccountMessage;
import pwc.taxtech.atms.common.message.EnterpriseAccountSetOrgMsg;
import pwc.taxtech.atms.common.message.LogMessage;
import pwc.taxtech.atms.constant.EnterpriseAccountConstant;
import pwc.taxtech.atms.constant.IndustryConstant;
import pwc.taxtech.atms.constant.enums.AccountRuleEnum;
import pwc.taxtech.atms.dao.AccountMappingManualMapper;
import pwc.taxtech.atms.dao.dao.AccountMappingManualDao;
import pwc.taxtech.atms.dao.dao.EnterpriseAccountDao;
import pwc.taxtech.atms.dao.dao.EnterpriseAccountSetOrgDao;
import pwc.taxtech.atms.dao.dao.StandardAccountDao;
import pwc.taxtech.atms.dto.OperationLogDto;
import pwc.taxtech.atms.dto.OperationResultDto;
import pwc.taxtech.atms.dto.UpdateLogParams;
import pwc.taxtech.atms.dto.ValidateInfoDto;
import pwc.taxtech.atms.dao.dao.AccountMappingDao;
import pwc.taxtech.atms.dto.accountmapping.AccountMappingManualDto;
import pwc.taxtech.atms.dto.epaccount.*;
import pwc.taxtech.atms.dto.stdaccount.StandardAccountDto;
import pwc.taxtech.atms.entitiy.*;
import pwc.taxtech.atms.service.AccountService;
import pwc.taxtech.atms.service.EnterpriseAccountService;
import pwc.taxtech.atms.service.EnterpriseAccountSetService;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class EnterpriseAccountServiceImpl extends AbstractService implements EnterpriseAccountService {

    @Autowired
    private AccountService accountService;
    @Autowired
    private EnterpriseAccountSetService enterpriseAccountSetService;
    @Autowired
    private FileService fileService;
    @Autowired
    private EnterpriseAccountDao enterpriseAccountDao;
    @Autowired
    private StandardAccountDao standardAccountDao;
    @Autowired
    private AccountMappingManualDao mappingManualDao;
    @Autowired
    private EnterpriseAccountSetOrgDao epAccountSetOrgDao;
    @Autowired
    private AccountMappingDao accountMappingDao;
    @Autowired
    private AccountMappingManualMapper mappingManualMapper;
    
    private Map<String, List<String>> mapParentAccountResult;
    
    
    /* (non-Javadoc)
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#getEnterpriseAccount(java.lang.String, java.lang.String)
     */
    @Override
    public EnterpriseAccount getEnterpriseAccount(String enterpriseAccountCode, String enterpriseAccountSetID) {
        EnterpriseAccountExample example = new EnterpriseAccountExample();
        example.createCriteria().andCodeEqualTo(enterpriseAccountCode).andEnterpriseAccountSetIDEqualTo(enterpriseAccountSetID);
        
        List<EnterpriseAccount> epAccounts = enterpriseAccountMapper.selectByExample(example);
        return CollectionUtils.isEmpty(epAccounts)?null:epAccounts.get(0);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#
     * getListByEnterpriseAccountSetID(java.lang.String)
     */
    @Override
    public EnterpriseAccountAndValidateInfo getListByEnterpriseAccountSetID(String enterpriseAccountSetID) {

        EnterpriseAccountExample enterpriseAccountExample = new EnterpriseAccountExample();
        enterpriseAccountExample.createCriteria()
            .andRuleTypeEqualTo(2)
            .andEnterpriseAccountSetIDEqualTo(enterpriseAccountSetID);
        enterpriseAccountExample.setOrderByClause("ParentCode ASC, IsActive DESC, Code ASC");
        List<EnterpriseAccount> epAccounts = enterpriseAccountMapper.selectByExample(enterpriseAccountExample);
        
        //no enterprise account
        if(epAccounts==null || epAccounts.isEmpty()) {
            return new EnterpriseAccountAndValidateInfo();
        }
        
        //get all standard accounts
        StandardAccountExample standardAccountExample = new StandardAccountExample();
        List<StandardAccount> stdAccounts = standardAccountMapper.selectByExample(standardAccountExample);
        
        //set stdName
        List<EnterpriseAccountDto> epAccountDtoList = new ArrayList<>();
        for(EnterpriseAccount epAccount: epAccounts) {
            EnterpriseAccountDto epAccountDto = new EnterpriseAccountDto();
            
            CommonUtils.copyProperties(epAccount, epAccountDto);
            epAccountDto.setParentName("");
            epAccountDto.setParentFullName("");
            epAccountDto.setStdName("");
            stdAccounts.stream().filter(stdAccount -> stdAccount.getCode().equals(epAccount.getStdCode())).findFirst()
                .ifPresent(stdAccount -> {epAccountDto.setStdName(stdAccount.getName());});
            epAccountDtoList.add(epAccountDto);
        }
        
        //wrap epAccounts and generate retEpAccountDtoList
        List<EnterpriseAccountDto> retEpAccountDtoList = new ArrayList<>();
        List<EnterpriseAccountDto> topEpAccountDtoList 
            = epAccountDtoList.stream().filter(epAccountDto -> epAccountDto.getParentCode() == null)
                .collect(Collectors.toList());
        for(EnterpriseAccountDto epAccountDto:  topEpAccountDtoList) {
            epAccountDto.setTreeLevel(0);
            retEpAccountDtoList.add(epAccountDto);
            retEpAccountDtoList.addAll(getWrapList(epAccountDto, epAccountDtoList));
        }
        
        //lost epAccounts list
        for(EnterpriseAccountDto epAccountDto:  epAccountDtoList) {
            if( !retEpAccountDtoList.contains(epAccountDto)) {
                retEpAccountDtoList.add(epAccountDto);
            }
        }
        
        //validate enterprise account list
        List<ValidateInfoDto> validateInfoList = validateEnterpriseAccountList(retEpAccountDtoList);
        
        EnterpriseAccountAndValidateInfo enterpriseAccountAndValidateInfo = new EnterpriseAccountAndValidateInfo();
        enterpriseAccountAndValidateInfo.setEnterpriseAccountList(retEpAccountDtoList);
        enterpriseAccountAndValidateInfo.setValidateInfoList(validateInfoList);
        
        return enterpriseAccountAndValidateInfo;
    }
    
    /* (non-Javadoc)
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#getEnterpriseAccount(java.lang.String)
     */
    @Override
    public EnterpriseAccountDto getEnterpriseAccount(String enterpriseAccountId) {
        
        EnterpriseAccount enterpriseAccount = enterpriseAccountMapper.selectByPrimaryKey(enterpriseAccountId);
        
        //get all enterprise accounts
        EnterpriseAccountExample enterpriseAccountExample = new EnterpriseAccountExample();
        enterpriseAccountExample.createCriteria()
            .andIsActiveEqualTo(CommonConstants.ACTIVE_STATUS)
            .andRuleTypeEqualTo(2)
            .andEnterpriseAccountSetIDEqualTo(enterpriseAccount.getEnterpriseAccountSetID());
        List<EnterpriseAccount> epAccounts = enterpriseAccountMapper.selectByExample(enterpriseAccountExample);
        
        //get all standard accounts
        StandardAccountExample standardAccountExample = new StandardAccountExample();
        List<StandardAccount> stdAccounts = standardAccountMapper.selectByExample(standardAccountExample);
        
        EnterpriseAccountDto enterpriseAccountDto = new EnterpriseAccountDto();
        CommonUtils.copyProperties(enterpriseAccount, enterpriseAccountDto);
        epAccounts.stream().filter(epAccount -> enterpriseAccount.getParentCode()!=null && enterpriseAccount.getParentCode().equals(epAccount.getCode())).findFirst()
            .ifPresent(epAccount -> {
                enterpriseAccountDto.setParentName(epAccount.getName());
                enterpriseAccountDto.setParentFullName(epAccount.getFullName());
                });
        stdAccounts.stream().filter(stdAccount -> stdAccount.getCode().equals(enterpriseAccount.getStdCode())).findFirst()
            .ifPresent(stdAccount -> {
                enterpriseAccountDto.setStdName(stdAccount.getName());
                });
        enterpriseAccountDto.setSubStdAccounts(new ArrayList<>());
        enterpriseAccountDto.setIndustryID("");
        
        return enterpriseAccountDto;
    }
    
    /* (non-Javadoc)
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#addEnterpriseAccount(pwc.taxtech.atms.service.dto.EnterpriseAccountDto)
     */
    @Override
    @Transactional
    public OperationResultDto<List<EnterpriseAccountDto>> addEnterpriseAccount(EnterpriseAccountDto enterpriseAccountDto) {

        if(enterpriseAccountDto == null) {
            return new OperationResultDto<>(false);
        }
        EnterpriseAccount entityToAdd = new EnterpriseAccount();
        CommonUtils.copyProperties(enterpriseAccountDto, entityToAdd);
        
        //check duplication ep account
        List<EnterpriseAccountDto> sameEpAccounts = getSameEnterpriseAccountList(enterpriseAccountDto);
        if(sameEpAccounts!=null && !sameEpAccounts.isEmpty()) {
            return new OperationResultDto<>(false, EnterpriseAccountMessage.EnterpriceAccountRepeat, sameEpAccounts);
        }
        //set parent account no leaf
        setParentIsNotLeaf(enterpriseAccountDto.getParentCode(), enterpriseAccountDto.getEnterpriseAccountSetID());
        //add enterprise accoun
        entityToAdd.setID(CommonUtils.getUUID());
        entityToAdd.setIsLeaf(true);
        entityToAdd.setCreateTime(new Date());
        entityToAdd.setUpdateTime(new Date());
        entityToAdd.setCreatorID(authUserHelper.getCurrentUserID());
        entityToAdd.setUpdatorID(authUserHelper.getCurrentUserID());
        enterpriseAccountMapper.insert(entityToAdd);
        
        //获取与之关联的机构
        EnterpriseAccountSetOrgExample example = new EnterpriseAccountSetOrgExample();
        example.createCriteria().andEnterpriseAccountSetIDEqualTo(enterpriseAccountDto.getEnterpriseAccountSetID());
        List<EnterpriseAccountSetOrg> accountSetOrgList = enterpriseAccountSetOrgMapper.selectByExampleWithAssociation(example);
        
        //构造数据结构,调用更新父级科目对应方法
        List<String> epAccountCodeList = new ArrayList<>();
        epAccountCodeList.add(entityToAdd.getCode());
        
        this.mapParentAccountResult = new HashMap<>();
        for(EnterpriseAccountSetOrg accountSetOrg : accountSetOrgList) {
            mapAccountUpdateParent(epAccountCodeList, accountSetOrg.getEnterpriseAccountSetID(), getConvertedIndustryID(accountSetOrg.getOrganization().getIndustryID()), accountSetOrg.getOrganizationID(), true);
        }
        
        //get enterprise set name
        EnterpriseAccountSet enterpriseAccountSet = enterpriseAccountSetMapper.selectByPrimaryKey(enterpriseAccountDto.getEnterpriseAccountSetID());
        //add operational log
        UpdateLogParams updateLogParams = new UpdateLogParams();
        updateLogParams.setOperationUser(authUserHelper.getCurrentAuditor());
        updateLogParams.setUpdateState("");
        updateLogParams.setOriginalState("");
        updateLogParams.setOperationContent(enterpriseAccountDto.getCode() + " " + enterpriseAccountDto.getName());
        updateLogParams.setOperationObject(enterpriseAccountSet.getName());
        updateLogParams.setOperationModule(OperationModule.BasicDataEnterpriceAccount.value());
        updateLogParams.setOperateLogType(OperateLogType.OperationLogEnterPrise.value());
        updateLogParams.setComment("");
        updateLogParams.setOperationAction(OperationAction.New.value());
        operationLogService.addOrDeleteDataAddLog(updateLogParams);
        
        return new OperationResultDto<>(true);
    }

    /* (non-Javadoc)
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#updateEnterpriseAccount(pwc.taxtech.atms.service.dto.EnterpriseAccountDto)
     */
    @Override
    @Transactional
    public OperationResultDto<List<EnterpriseAccountDto>> updateEnterpriseAccount(EnterpriseAccountDto enterpriseAccountDto) {

        if(enterpriseAccountDto == null) {
            return new OperationResultDto<>(false);
        }
        
        EnterpriseAccount entityToUpdate = enterpriseAccountMapper.selectByPrimaryKey(enterpriseAccountDto.getID());
        if(entityToUpdate == null) {
            return new OperationResultDto<>(false);
        }
        
        //check duplication ep account
        List<EnterpriseAccountDto> sameEpAccounts = getSameEnterpriseAccountList(enterpriseAccountDto);
        if(sameEpAccounts!=null && !sameEpAccounts.isEmpty()) {
            return new OperationResultDto<>(false, EnterpriseAccountMessage.EnterpriceAccountRepeat, sameEpAccounts);
        }
        
        //copy entityToUpdate
        EnterpriseAccount entityCopy = new EnterpriseAccount();
        CommonUtils.copyProperties(entityToUpdate, entityCopy);
        
        if(entityCopy.getParentCode()!=null && !entityCopy.getParentCode().equals(enterpriseAccountDto.getParentCode())) {
            // reset the isleaf
            setParentIsNotLeaf(enterpriseAccountDto.getParentCode(), enterpriseAccountDto.getEnterpriseAccountSetID());
            setParentLeaf(entityCopy.getParentCode(), enterpriseAccountDto.getEnterpriseAccountSetID(), enterpriseAccountDto.getID());
        }
        
        
        //查询所有原本对应子科目
        //如修改的为父科目, 需要级联修改其所有子科目的父科目代码以及名字
        EnterpriseAccountExample enterpriseAccountexample = new EnterpriseAccountExample();
        enterpriseAccountexample.createCriteria()
            .andParentCodeEqualTo(entityCopy.getCode())
            .andEnterpriseAccountSetIDEqualTo(enterpriseAccountDto.getEnterpriseAccountSetID());
        List<EnterpriseAccount> childrenAccountList = enterpriseAccountMapper.selectByExample(enterpriseAccountexample);
        if(childrenAccountList!=null && !childrenAccountList.isEmpty()) {
            if(!entityCopy.getCode().equals(enterpriseAccountDto.getCode()) || !entityCopy.getName().equals(enterpriseAccountDto.getName())) {
                for(EnterpriseAccount childrenAccount: childrenAccountList) {
                    childrenAccount.setParentCode(enterpriseAccountDto.getCode());
                    childrenAccount.setFullName(enterpriseAccountDto.getFullName() + EnterpriseAccountConstant.FullNameSeparator + childrenAccount.getName());
                    enterpriseAccountMapper.updateByPrimaryKey(childrenAccount);
                }
            }
        }
        
        entityToUpdate.setCode(enterpriseAccountDto.getCode());
        entityToUpdate.setName(enterpriseAccountDto.getName());
        entityToUpdate.setFullName(enterpriseAccountDto.getFullName());
        entityToUpdate.setParentCode(enterpriseAccountDto.getParentCode());
        entityToUpdate.setDirection(enterpriseAccountDto.getDirection());
        entityToUpdate.setAcctProp(enterpriseAccountDto.getAcctProp());
        entityToUpdate.setStdCode(enterpriseAccountDto.getStdCode());
        enterpriseAccountMapper.updateByPrimaryKey(entityToUpdate);
        
        //获取与之关联的机构
        EnterpriseAccountSetOrgExample example = new EnterpriseAccountSetOrgExample();
        example.createCriteria().andEnterpriseAccountSetIDEqualTo(enterpriseAccountDto.getEnterpriseAccountSetID());
        List<EnterpriseAccountSetOrg> accountSetOrgList = enterpriseAccountSetOrgMapper.selectByExampleWithAssociation(example);
        
        //构造数据结构,调用更新父级科目对应方法
        List<String> epAccountCodeList = new ArrayList<>();
        epAccountCodeList.add(entityToUpdate.getCode());
        
        this.mapParentAccountResult = new HashMap<>();
        for(EnterpriseAccountSetOrg accountSetOrg : accountSetOrgList) {
            if(entityToUpdate.getParentCode()!=null && entityToUpdate.getParentCode().equals(entityCopy.getParentCode())) {
                
                /* @See below C#代码 EnterpriseAccountService.cs Line 238-240
                 * string updateSql = "UPDATE AccountMapping SET StandardAccountCode='00' WHERE EnterpriseAccountCode={0} AND EnterpriseAccountSetID={1} AND OrganizationID={2} AND IndustryID={3}";
                   _dbContext.Database.ExecuteSqlCommand(updateSql, entity.ID, item.EnterpriseAccountSetID, item.OrganizationID, GetConvertedIndustryID(item.IndustryID));
                 * EnterpriseAccountCode 参数应该设错了
                 */
                
                //需要清除旧的对应关系
                AccountMapping accountMapping = new AccountMapping();
                accountMapping.setStandardAccountCode("00");
                AccountMappingExample accountMappingExample = new AccountMappingExample();
                accountMappingExample.createCriteria()
                    .andEnterpriseAccountCodeEqualTo(entityCopy.getParentCode())
                    .andEnterpriseAccountSetIDEqualTo(accountSetOrg.getEnterpriseAccountSetID())
                    .andOrganizationIDEqualTo(accountSetOrg.getOrganizationID())
                    .andIndustryIDEqualTo(getConvertedIndustryID(accountSetOrg.getOrganization().getIndustryID()));
                accountMappingMapper.updateByExampleSelective(accountMapping, accountMappingExample);
            }
            mapAccountUpdateParent(epAccountCodeList, accountSetOrg.getEnterpriseAccountSetID(), 
                     getConvertedIndustryID(accountSetOrg.getOrganization().getIndustryID()), accountSetOrg.getOrganizationID(), true);
        }
        //get enterprise set name
        EnterpriseAccountSet enterpriseAccountSet = enterpriseAccountSetMapper.selectByPrimaryKey(enterpriseAccountDto.getEnterpriseAccountSetID());
        //operation log
        UpdateLogParams updateLogParams = new UpdateLogParams();
        updateLogParams.setOperationUser(authUserHelper.getCurrentAuditor());
        updateLogParams.setUpdateState(getEnterpriseAccountInfo(entityToUpdate));
        updateLogParams.setOriginalState(getEnterpriseAccountInfo(entityCopy));
        updateLogParams.setOperationContent(enterpriseAccountDto.getCode() + " " + enterpriseAccountDto.getName());
        updateLogParams.setOperationObject(enterpriseAccountSet.getName());
        updateLogParams.setOperationModule(OperationModule.BasicDataEnterpriceAccount.value());
        updateLogParams.setOperateLogType(OperateLogType.OperationLogEnterPrise.value());
        updateLogParams.setComment("");
        updateLogParams.setOperationAction(OperationAction.UpdateEnterpriseAccount.value());
        operationLogService.addOrDeleteDataAddLog(updateLogParams);
        
        enableEnterpriseAccountSet(enterpriseAccountDto.getEnterpriseAccountSetID());
        
        return new OperationResultDto<>(true);
    }
    
    
    /* (non-Javadoc)
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#mapAccountUpdateParent(java.util.List, java.lang.String, java.lang.String, java.lang.String, java.lang.Boolean)
     */
    @Override
    public void mapAccountUpdateParent(List<String> enterpriseAccountCodeList, String enterpriseAccountSetID,
            String industryID, String orgID, Boolean isToUpdateEvenExists) {

        for (String epAccountCode : enterpriseAccountCodeList) {
            
            /* 数据准备 start */
            String mappedStdCode = "";
            
            //第一步:通过企业科目Code获取企业科目对象
            EnterpriseAccountExample enterpriseAccountExample = new EnterpriseAccountExample();
            enterpriseAccountExample.createCriteria()
                .andEnterpriseAccountSetIDEqualTo(enterpriseAccountSetID)
                .andCodeEqualTo(epAccountCode);
            List<EnterpriseAccount> epAccounts = enterpriseAccountMapper.selectByExample(enterpriseAccountExample);
            if(CollectionUtils.isEmpty(epAccounts)) {
                continue;
            }
            EnterpriseAccount epAccount = epAccounts.get(0);
            //如果当前对应的本身就是第一级,不需要再考虑
            if(epAccount.getParentCode() == null || epAccount.getParentCode().isEmpty()) {
                continue;
            }
            
            //第二步: 通过上一步获取到的企业科目对象的ParentCode获取企业企业科目对象
            enterpriseAccountExample = new EnterpriseAccountExample();
            enterpriseAccountExample.createCriteria()
                .andEnterpriseAccountSetIDEqualTo(enterpriseAccountSetID)
                .andCodeEqualTo(epAccount.getParentCode());
            List<EnterpriseAccount> parentEpAccounts = enterpriseAccountMapper.selectByExample(enterpriseAccountExample);
            if(CollectionUtils.isEmpty(parentEpAccounts)) {
                return; //C# return
            }
            EnterpriseAccount parentEpAccount = parentEpAccounts.get(0);
            
            //第三步: 通过Parent企业科目对象获取该ParentCode下面的所有子企业科目
            List<EnterpriseAccount> childrenEpAccountList = getMappingResultByParentCode(parentEpAccount.getCode(), enterpriseAccountSetID, industryID, orgID);
            
            //第四步: 判断第三步获取到企业科目中,标准科目为空的个数
            if(CollectionUtils.isEmpty(childrenEpAccountList)) {
                continue;
            }
            long emptyStdCodeCount = childrenEpAccountList.stream().filter(sa -> sa.getStdCode()==null || sa.getStdCode().isEmpty()).count();
            
            //第五部: 将第三步获取到的所有企业科目取出其中的StdCode并去重
            List<String> uniqueStdCodeList = childrenEpAccountList.stream()
                    .filter(sa -> sa.getStdCode()!=null && !sa.getStdCode().isEmpty())
                    .map(sa -> sa.getStdCode()).collect(Collectors.toList());
            /* 数据准备 end */
            
            /* 业务处理 start */
            
            //等于0说明子科目全部都有对应上
            if(emptyStdCodeCount == 0) {
                
                long countOfDistinctStdCode = uniqueStdCodeList.size();
                
                //等于1说明对应上的标准科目都是同一个
                if(countOfDistinctStdCode == 1) {
                    //2. 手动对应,子科目完全对应的时候并且都对应到同一个标准科目,那么父级也要对应到该标准科目
                    mappedStdCode = uniqueStdCodeList.get(0);
                }
                //说明虽然完全对应上了,但是对应上的标准科目代码不唯一
                else {
                    
                    //3. 手动对应,子科目完全对应的时候但是没有对应到同一个标准科目
                    StandardAccountExample standardAccountExample = new StandardAccountExample();
                    standardAccountExample.createCriteria()
                        .andCodeIn(uniqueStdCodeList).andIndustryIDEqualTo(industryID);
                    List<StandardAccount> standardAccountList = standardAccountMapper.selectByExample(standardAccountExample);
                    if(CollectionUtils.isEmpty(standardAccountList)) {
                        continue;
                    }
                    List<String> distinctStdParentCodeList = standardAccountList.stream()
                            .map(sa -> sa.getParentCode()).distinct().collect(Collectors.toList());
                    long uniqueStdParentCodeCount = distinctStdParentCodeList.size();
                    
                    //等于1说明对应上的都属于同一个父级标准科目
                    if(uniqueStdParentCodeCount == 1 
                            && distinctStdParentCodeList.get(0)!=null && !distinctStdParentCodeList.get(0).isEmpty() 
                            && !uniqueStdCodeList.contains("0000")) {
                        //子科目完全对应的时候但是没有对应到同一个标准科目但是属于同一个父科目下,那么该企业科目的父级也要对应到该标准科目的父级
                        mappedStdCode = standardAccountList.get(0).getParentCode();
                    }
                    else {
                        //子科目完全对应的时候但是没有对应到同一个标准科目又不属于同一个父科目下,那么该企业科目的父级显示为横线 -
                        mappedStdCode = CommonConstants.EmptyStdCode;
                    }
                }
            }
            else {
                //4.  手动对应,子科目没有全对应的时候,那么父级科目显示为未对应
                mappedStdCode = null;
            }
            
            /* 更新UI准备  start */
            StandardAccount stdAccount = new StandardAccount();
            if(mappedStdCode == CommonConstants.EmptyStdCode) {
                stdAccount.setCode(CommonConstants.EmptyStdCode);
                stdAccount.setName("");
            }
            else if(mappedStdCode == null) {
                stdAccount.setCode(null);
                stdAccount.setName("");
            }
            else {
                StandardAccountExample standardAccountExample = new StandardAccountExample();
                standardAccountExample.createCriteria()
                    .andCodeEqualTo(mappedStdCode)
                    .andIndustryIDEqualTo(industryID);
                List<StandardAccount> stdAccountList = standardAccountMapper.selectByExample(standardAccountExample);
                if (CollectionUtils.isEmpty(stdAccountList)) {
                    continue;
                }
                stdAccount = stdAccountList.get(0);
            }
            addMapParentAccountResult(parentEpAccount.getCode(), Arrays.asList(stdAccount.getCode(), stdAccount.getName()));
            
            //更新该企业科目的标准科目为mappedStdCode
            accountService.mapStdAccountByCode(enterpriseAccountSetID, stdAccount.getCode(), epAccountCode, industryID, orgID, isToUpdateEvenExists, 0);
            
            /* 更新UI准备  end */
            /* 业务处理 end */
            
            /* 如果还存在上一级的情况,所以递归处理 start */
            mapAccountUpdateParent(Arrays.asList(parentEpAccount.getCode()), enterpriseAccountSetID, industryID, orgID, isToUpdateEvenExists);
            /* 如果还存在上一级的情况,所以递归处理 end */
        }
    }

    /* (non-Javadoc)
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#createEnterpriseAccountSetAndimportEnterpriseAccount(java.lang.String, java.lang.String, java.util.List)
     */
    @SuppressWarnings("rawtypes")
    @Override
    @Transactional
    public OperationResultDto addEnterpriseAccountSetAndImportData(String enterpriseAccountSetName,
            String enterpriseAccountSetCode, List<EnterpriseAccountDto> importData) {
        
        EnterpriseAccountSetDto enterpriseAccountSetDto = new EnterpriseAccountSetDto();
        enterpriseAccountSetDto.setName(enterpriseAccountSetName);
        enterpriseAccountSetDto.setCode(enterpriseAccountSetCode);
        //validate name is duplicated
        OperationResultDto<?> nameValidate = enterpriseAccountSetService.enterpriseAccountSetNameValidate(enterpriseAccountSetDto);
        if(!nameValidate.getResult()) {
            return nameValidate;
        }
        //validate code is duplicated
        OperationResultDto<?> codeValidate = enterpriseAccountSetService.enterpriseAccountSetCodeValidate(enterpriseAccountSetDto);
        if(!codeValidate.getResult()) {
            return codeValidate;
        }
        
        //save enterprise account set
        EnterpriseAccountSet enterpriseAccountSet = new EnterpriseAccountSet();
        CommonUtils.copyProperties(enterpriseAccountSetDto, enterpriseAccountSet);
        enterpriseAccountSet.setID(CommonUtils.getUUID());
        enterpriseAccountSet.setIsActive(CommonConstants.ACTIVE_STATUS);
        enterpriseAccountSet.setCreateTime(new Date());
        enterpriseAccountSet.setUpdateTime(new Date());
        enterpriseAccountSet.setCreatorID(authUserHelper.getCurrentUserID());
        enterpriseAccountSetMapper.insert(enterpriseAccountSet);
        
        //create operationlog for creating enterprise account set
        UpdateLogParams updateLogParams = new UpdateLogParams();
        updateLogParams.setOperationUser(authUserHelper.getCurrentAuditor());
        updateLogParams.setUpdateState("");
        updateLogParams.setOriginalState("");
        updateLogParams.setOperationContent("");
        updateLogParams.setOperationModule(OperationModule.BasicDataEnterpriceAccount.value());
        updateLogParams.setComment("");
        updateLogParams.setOperateLogType(OperateLogType.OperationLogEnterPrise.value());
        updateLogParams.setOperationAction(OperationAction.AddEnterpriseAccountSet.value());
        updateLogParams.setOperationObject(enterpriseAccountSet.getName());
        operationLogService.addOrDeleteDataAddLog(updateLogParams);
        
        //nothing to import
        if(importData == null && CollectionUtils.isEmpty(importData)) {
            return OperationResultDto.success();
        }
        
        importDataProcess(importData, enterpriseAccountSet.getID(), true);
        
        return OperationResultDto.success();
    }
    

    /* (non-Javadoc)
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#repeatImportEnterpriseAccountSet(pwc.taxtech.atms.dto.epaccount.EnterpriseAccountSetDto, java.util.List)
     */
    @SuppressWarnings("rawtypes")
    @Override
    @Transactional
    public OperationResultDto repeatImportEnterpriseAccountSet(EnterpriseAccountSetDto enterpriseAccountSetDto,
            List<EnterpriseAccountDto> importData) {

        return importDataProcess(importData, enterpriseAccountSetDto.getID(), enterpriseAccountSetDto.getIsImportAppend());
    }

    
    /* (non-Javadoc)
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#clearRepeatEnterpriseAccountList(pwc.taxtech.atms.dto.epaccount.EnterpriseAccountSetDto)
     */
    @SuppressWarnings("rawtypes")
    @Override
    public OperationResultDto clearRepeatEnterpriseAccountList(EnterpriseAccountSetDto enterpriseAccountSetDto) {
        
        EnterpriseAccountExample enterpriseAccountExample = new EnterpriseAccountExample();
        enterpriseAccountExample.createCriteria()
            .andEnterpriseAccountSetIDEqualTo(enterpriseAccountSetDto.getID());
        List<EnterpriseAccount> epAccountList = enterpriseAccountMapper.selectByExample(enterpriseAccountExample);
        
        if(enterpriseAccountSetDto.getRepeatCodeList() == null && enterpriseAccountSetDto.getRepeatCodeList().isEmpty()) {
            return OperationResultDto.success();
        }
        
        //删除重复项 留1个
        for(String repeatCode: enterpriseAccountSetDto.getRepeatCodeList()) {
            List<EnterpriseAccount> repeatedEpAccountList = epAccountList.stream()
                    .filter(sa -> sa.getCode().equals(repeatCode)).collect(Collectors.toList());
            for(int i=0; i<repeatedEpAccountList.size()-1; i++) {
                enterpriseAccountMapper.deleteByPrimaryKey(repeatedEpAccountList.get(i).getID());
            }
        }
        
        enableEnterpriseAccountSet(enterpriseAccountSetDto.getID());
        
        return OperationResultDto.success();
    }

    /**
     * Generate by-level wrapped enterprise Account list
     * @param currentEpAccountDto
     * @param epAccountDtoList
     * @return List<EnterpriseAccountDto>
     */
    private List<EnterpriseAccountDto> getWrapList(EnterpriseAccountDto currentEpAccountDto, List<EnterpriseAccountDto> epAccountDtoList) {
        
        List<EnterpriseAccountDto> result = new ArrayList<>();
        List<EnterpriseAccountDto> subList = epAccountDtoList.stream()
                .filter(epAccountDto -> currentEpAccountDto.getCode().equals(epAccountDto.getParentCode()))
                .collect(Collectors.toList());
        
        if(subList!=null && !subList.isEmpty()) {
            for(EnterpriseAccountDto sub: subList) {
                sub.setTreeLevel(currentEpAccountDto.getTreeLevel()+1);
                sub.setParentName(currentEpAccountDto.getName());
                sub.setParentFullName(currentEpAccountDto.getFullName());
                result.add(sub);
                List<EnterpriseAccountDto> tempList = getWrapList(sub, epAccountDtoList);
                if(tempList!=null && !tempList.isEmpty()) {
                    result.addAll(tempList);
                }
            }
        }
        return result;
    }
    
    
    /* (non-Javadoc)
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#getAccountMappingOrg(java.lang.String)
     */
    @Override
    public List<AccountMappingDto> getAccountMappingOrg(String organizationID) {

        AccountMappingExample accountMappingExample = new AccountMappingExample();
        accountMappingExample.createCriteria()
            .andOrganizationIDEqualTo(organizationID);
        List<AccountMapping> accountMappingList = accountMappingMapper.selectByExample(accountMappingExample);
        
        List<AccountMappingDto> accountMappingDtoList = new ArrayList<>();
        accountMappingList.stream().forEach(accountMapping -> {
            AccountMappingDto accountMappingDto = new AccountMappingDto();
            accountMappingDto.setIndustryID(accountMapping.getIndustryID());
            accountMappingDto.setOrganizationID(accountMapping.getOrganizationID());
            accountMappingDtoList.add(accountMappingDto);
        });
        return accountMappingDtoList;
    }

    @Override
    public List<EnterpriseAccountSetDto> getEnterpriseAccountSetListByOrgID(String orgId) {
        if (StringUtils.isBlank(orgId)) {
            return Collections.emptyList();
        }
        return enterpriseAccountSetMapper.getAccountDtoByOrgId(orgId).stream()
                .map(this::toAccountSetDto).collect(Collectors.toList());
    }

    @Override
    public List<EnterpriseAccountDto> getList(String epAccountSetID, String orgId, String filterType) {
        if (StringUtils.isAnyBlank(epAccountSetID, orgId)) {
            return Collections.emptyList();
        }
        Organization organization = organizationMapper.selectByPrimaryKey(orgId);
        Industry industry = industryMapper.selectByPrimaryKey(organization.getIndustryID());
        String industryId = null == industry ? IndustryConstant.GeneralIndustryID : industry.getID();
        List<EnterpriseAccountDto> dtoList = enterpriseAccountMapper.getDto(epAccountSetID, orgId, industryId);
//        dtoList = dtoList.stream().map(x -> {
//            if (StringUtils.isBlank(x.getParentCode())) {
//                x.setParentCode(StringUtils.EMPTY);
//            }
//            return x;
//        }).sorted(Comparator.comparing(EnterpriseAccountDto::getParentCode)
//                .thenComparing(EnterpriseAccountDto::getIsActive).reversed()
//                .thenComparing(EnterpriseAccountDto::getCode)).collect(Collectors.toList());
        List<EnterpriseAccountDto> result;
        switch (filterType) {
            //未对应
            case "0":
                result = dtoList.stream().filter(x -> StringUtils.isBlank(x.getStdCode())).collect(Collectors.toList());
                break;
            //已对应
            case "1":
                result = dtoList.stream().filter(x -> StringUtils.isNotBlank(x.getStdCode())).collect(Collectors.toList());
                break;
            //借贷方向不一致
            case "2":
                result = dtoList.stream().filter(x -> StringUtils.isNotBlank(x.getStdCode())
                        && !StringUtils.equalsAny(x.getStdCode(), EnterpriseAccountConstant.StdCode.EMPTY_STD_CODE, EnterpriseAccountConstant.StdCode.NULL_STD_CODE)
                        && x.getDirection() != x.getStdDirection()).collect(Collectors.toList());
                break;
            //科目类型不一致
            case "3":
                result = dtoList.stream().filter(x -> StringUtils.isNotBlank(x.getStdCode())
                        && !StringUtils.equalsAny(x.getStdCode(), EnterpriseAccountConstant.StdCode.EMPTY_STD_CODE, EnterpriseAccountConstant.StdCode.NULL_STD_CODE)
                        && x.getAcctProp() != x.getStdAcctProp()).collect(Collectors.toList());
                break;
            default:
                result = dtoList;
        }
        List<EnterpriseAccountDto> rootList = result.stream().filter(x -> StringUtils.isBlank(x.getParentCode())).map(x -> {
            x.setTreeLevel(0);
            return x;
        }).collect(Collectors.toList());
        List<EnterpriseAccountDto> total = Lists.newArrayList();
        formatEpAccountDtoTree(rootList, result, total);
        return total.stream().sorted(Comparator.comparing(EnterpriseAccountDto::getCode)).collect(Collectors.toList());
    }

    @Transactional
    @Override
    public OperationResultDto autoMap(String orgId, String accountSetId) {
        //region 基础数据获取
        Optional<EnterpriseAccountSetOrg> optional = epAccountSetOrgDao.getByOrgIdAndAccountSetId(orgId, accountSetId)
                .stream().findFirst();
        Organization org = organizationMapper.selectByPrimaryKey(orgId);
        if (optional.isPresent() && null != org) {
            EnterpriseAccountSetOrg setOrg = optional.get();
            String industryId = org.getIndustryID();

            //标准科目准则
            int ruleId = AccountRuleEnum.Rule2007.getValue();

            //获取账套信息便于存储日志
            EnterpriseAccountSet accountSet = new EnterpriseAccountSet();
            //endregion

            //region 获取基础信息

            //获取指定企业账套下的企业科目集合并转化为DTO
            List<EnterpriseAccount> epAccountList = enterpriseAccountDao.getByEpAccountSetId(setOrg.getEnterpriseAccountSetID());
            List<EnterpriseAccountDto> accountDtoList = epAccountList.stream().map(x -> {
                return CommonUtils.copyProperties(x, new EnterpriseAccountDto());
            }).collect(Collectors.toList());

            //获取与该机构行业相同的标准科目集合并转化为DTO
            List<StandardAccount> stdAccountList = standardAccountDao.getByIndustryId(industryId).get();
            List<StandardAccountDto> stdAccountDtoList = epAccountList.stream().map(x -> {
                return CommonUtils.copyProperties(x, new StandardAccountDto());
            }).collect(Collectors.toList());

            //获取叶子节点标准科目集合
            List<StandardAccountDto> stdAccountLeafList = stdAccountDtoList.stream().filter(x -> x.isLeaf).collect(Collectors.toList());
            List<AccountMappingManual> allAccountMappingManualList = mappingManualDao.getAll().get();

            accountSet = enterpriseAccountSetMapper.selectByPrimaryKey(accountSetId);
            //endregion

            //region Step 0: 从手动对应库优先获取对应关系
            applyPriorityKeywords(accountDtoList, allAccountMappingManualList, accountSetId, orgId, industryId);
            //endregion

            //region Step 1: 匹配企业科目全称FullName与标准科目FullName完全一致
            //Step 1: Map accounts which name is identical to standard code fullname
            for (StandardAccountDto stdAccount : stdAccountLeafList) {
                Optional<EnterpriseAccountDto> account = accountDtoList.stream().filter(x -> StringUtils.equals(x.getFullName(),
                        stdAccount.getFullName())).findFirst();
                if (account.isPresent() && StringUtils.isNotBlank(account.get().getCode())) {
                    if (account.get().getIsLeaf()) {
                        accountMappingDao.mapStdAccountByCode(setOrg.getEnterpriseAccountSetID(), stdAccount.getCode(),
                                account.get().getCode(), industryId, orgId, false, 0);
                    } else {
                        List<EnterpriseAccountDto> relatedAccounts = accountDtoList.stream().filter(x -> StringUtils.startsWith(x.getCode()
                                , account.get().getCode())).collect(Collectors.toList());
                        // in case user has already mapped some of the leaf accounts and we do not want to overwrite them, otherwise just loop all and map all.
                        // now use recursion to map one by one...
                        mapAllChildrenRecursively(orgId, industryId, setOrg.getEnterpriseAccountSetID(),
                                account.get().getCode(), stdAccount.getCode(), relatedAccounts, false);
                    }
                }
            }
            //endregion

            //region Step 2: 匹配关键字库AccountMappingKeyword
            List<EnterpriseAccountDto> accountList = enterpriseAccountDao.getAccountMappingResult(setOrg.getEnterpriseAccountSetID(), ruleId, industryId);
            accountDtoList = getAllActiveAccounts(orgId, industryId, setOrg.getEnterpriseAccountSetID(), false); //rdbDisplayPart.Checked 只显示有期初余额或有凭证的科目
            for (EnterpriseAccountDto account : accountList) {
                EnterpriseAccountDto crtAccount = account;
                if (accountDtoList.stream().anyMatch(x -> StringUtils.equals(x.getCode(), account.getCode()))) {
                    List<EnterpriseAccountDto> mappingAccounts = accountDtoList.stream()
                            .filter(x -> StringUtils.equals(x.getCode(), account.getCode())).collect(Collectors.toList());
                    //查找C_AccountMappingKeyword中是否有关键字与当前科目的FullName完全匹配
                    for (EnterpriseAccountDto a : mappingAccounts) {
                        Optional<EnterpriseAccountDto> identicalMappedAccount = accountList.stream().filter(x -> StringUtils.equals(x.getCode(), a.getCode()) &&
                                StringUtils.equals(x.getMappingFullName(), a.getFullName())).findFirst();
                        if (identicalMappedAccount.isPresent()) {
                            crtAccount = identicalMappedAccount.get();
                            break;
                        }
                    }

                    if (crtAccount.getIsLeaf()) {
                        accountMappingDao.mapStdAccountByCode(setOrg.getEnterpriseAccountSetID(), crtAccount.getStdCode(),
                                crtAccount.getCode(), industryId, orgId, false, 0);
                    } else {
                        EnterpriseAccountDto finalCrtAccount = crtAccount;
                        List<EnterpriseAccountDto> relatedAccounts = accountDtoList.stream().filter(x -> StringUtils.startsWith(x.getCode(),
                                finalCrtAccount.getCode())).collect(Collectors.toList());
                        // in case user has already mapped some of the leaf accounts and we do not want to overwrite them, otherwise just loop all and map all.
                        // now use recursion to map one by one...
                        mapAllChildrenRecursively(orgId, industryId, setOrg.getEnterpriseAccountSetID(), crtAccount.getCode(),
                                crtAccount.getStdCode(), relatedAccounts, false);
                    }
                }
            }
            //endregion

            //region Step 3: Map 2nd or lower level of accounts which can be mapped to "其他"
            //Step 3: Map 2nd or lower level of accounts which can be mapped to "其他"
            accountDtoList = getAllActiveAccounts(orgId, industryId, setOrg.getEnterpriseAccountSetID(), false); //rdbDisplayPart.Checked 只显示有期初余额或有凭证的科目

            List<EnterpriseAccountDto> accountsUnmappedList = accountDtoList.stream().filter(x -> StringUtils.isBlank(x.getStdCode())
                    && x.getAcctLevel() > 1).collect(Collectors.toList());
            for (EnterpriseAccountDto accountsUnmapped : accountsUnmappedList) {
                String accountsUnmappedParent = accountsUnmapped.getParentCode();
                List<EnterpriseAccountDto> accountsUnmappedBrothers = accountDtoList.stream().filter(x -> StringUtils.equals(x.getParentCode(),
                        accountsUnmappedParent) && StringUtils.isNotBlank(x.getStdCode()) && !StringUtils.equals(x.getStdCode(),
                        CommonConstants.EmptyStdCode) && !StringUtils.equals(x.getStdCode(), CommonConstants.DashSignSeparator))
                        .sorted(Comparator.comparingInt(a -> a.getStdCode().length())).collect(Collectors.toList());
                EnterpriseAccountDto accountsUnmappedBrother;
                if (CollectionUtils.isNotEmpty(accountsUnmappedBrothers)) {
                    accountsUnmappedBrother = accountsUnmappedBrothers.get(0);
                    List<StandardAccountDto> stdAccountss = stdAccountDtoList.stream().filter(x -> StringUtils.equals(x.getCode(),
                            accountsUnmappedBrother.getStdCode())).collect(Collectors.toList());
                    StandardAccountDto stdAccount;
                    if (CollectionUtils.isNotEmpty(stdAccountss)) {
                        stdAccount = stdAccountss.get(0);
                        List<StandardAccountDto> stdAccountOthers = stdAccountLeafList.stream().filter(x -> StringUtils.equals(x.getParentCode(),
                                stdAccount.getParentCode()) && StringUtils.equals(x.getName(), EnterpriseAccountConstant.StrOthers)).collect(Collectors.toList());//其他
                        if (CollectionUtils.isNotEmpty(stdAccountOthers)) {
                            StandardAccountDto stdAccountOther = stdAccountOthers.get(0);
                            if (accountsUnmapped.getIsLeaf()) {
                                accountMappingDao.mapStdAccountByCode(setOrg.getEnterpriseAccountSetID(), stdAccountOther.getCode(),
                                        accountsUnmapped.getCode(), industryId, orgId, false, 0);
                            } else {
                                List<EnterpriseAccountDto> relatedAccounts = accountDtoList.stream().filter(x -> StringUtils.startsWith(x.getCode(),
                                        accountsUnmapped.getCode())).collect(Collectors.toList());
                                mapAllChildrenRecursively(orgId, industryId, setOrg.getEnterpriseAccountSetID(),
                                        accountsUnmapped.getCode(), stdAccountOther.getCode(), relatedAccounts, true);
                            }
                        }
                    }
                }
            }
            //endregion

            //region Step 4: Update the mapping of all parents
            //Step 4: Update the mapping of all parents
            accountDtoList = getAllActiveAccounts(orgId, industryId, setOrg.getEnterpriseAccountSetID(), false); //rdbDisplayPart.Checked 只显示有期初余额或有凭证的科目

            List<EnterpriseAccountDto> accountParents = accountDtoList.stream().filter(x -> StringUtils.isBlank(x.getStdCode()) &&
                    !x.getIsLeaf()).sorted(Comparator.comparingInt(EnterpriseAccountDto::getAcctLevel).reversed()).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(accountParents)) {
                List<EnterpriseAccountDto> accountParentList = accountParents;
                for (EnterpriseAccountDto accountParent : accountParentList) {
                    List<EnterpriseAccountDto> accountParentChildList = accountDtoList.stream().filter(x -> StringUtils
                            .equals(x.getParentCode(), accountParent.getCode())).collect(Collectors.toList());
                    List<EnterpriseAccountDto> accountParentChildMappedList = accountParentChildList.stream().filter(x -> StringUtils
                            .isNotBlank(x.getStdCode())).collect(Collectors.toList());
                    boolean isAllMappedSame = true;
                    //All children accounts are mapped
                    if (accountParentChildList.size() == accountParentChildMappedList.size() && CollectionUtils.isNotEmpty(accountParentChildList)) {
                        String mappedStdCode = accountParentChildList.get(0).getStdCode();
                        for (EnterpriseAccountDto accountParentChild : accountParentChildList) {
                            if (!StringUtils.equalsIgnoreCase(mappedStdCode, accountParentChild.getStdCode())) {
                                isAllMappedSame = false;
                                break;
                            }
                        }
                        if (isAllMappedSame) {
                            accountMappingDao.mapStdAccountByCode(setOrg.getEnterpriseAccountSetID(), mappedStdCode, accountParent.getCode(),
                                    industryId, orgId, false, 0);
                            EnterpriseAccountDto account = accountDtoList.stream().filter(x -> StringUtils.equals(x.getCode(), accountParent.getCode())).findFirst().get();
                            account.setStdCode(mappedStdCode);
                        } else {
                            //if all child accounts map to the same parent stdcode, save the parent stdcode.
                            //otherwise, same "0000" and display "-"
                            List<StandardAccountDto> mappedStdAccounts = stdAccountDtoList.stream().filter(x -> StringUtils.equals(x.getCode(),
                                    mappedStdCode)).collect(Collectors.toList());
                            StandardAccountDto mappedStdAccount = new StandardAccountDto();
                            boolean isAllMappedSameParent = true;
                            if (CollectionUtils.isNotEmpty(mappedStdAccounts)) {
                                mappedStdAccount = mappedStdAccounts.get(0);
                                for (EnterpriseAccountDto accountParentChild : accountParentChildList) {
                                    StandardAccountDto accountParentChildStdAccount = new StandardAccountDto();
                                    List<StandardAccountDto> accountParentChildStdAccounts = stdAccountDtoList.stream().filter(x ->
                                            StringUtils.equals(x.getCode(), accountParentChild.getStdCode())).collect(Collectors.toList());
                                    if (CollectionUtils.isNotEmpty(accountParentChildStdAccounts)) {
                                        accountParentChildStdAccount = accountParentChildStdAccounts.get(0);
                                        if (!StringUtils.equalsIgnoreCase(mappedStdAccount.getParentCode(), accountParentChildStdAccount.getParentCode())) {
                                            isAllMappedSameParent = false;
                                            break;
                                        }
                                    } else {
                                        isAllMappedSameParent = false;
                                    }
                                }
                            } else {
                                isAllMappedSameParent = false;
                            }
                            EnterpriseAccountDto account = accountDtoList.stream().filter(x -> StringUtils.equals(x.getCode(),
                                    accountParent.getCode())).findFirst().get();
                            if (isAllMappedSameParent) {
                                accountMappingDao.mapStdAccountByCode(setOrg.getEnterpriseAccountSetID(), mappedStdAccount.getParentCode(),
                                        accountParent.getCode(), industryId, orgId, true, 0);
                            } else {
                                mapParentAccountResult = Maps.newHashMap();
                                List<String> codeList = Lists.newArrayList();
                                if (CollectionUtils.isNotEmpty(accountParentChildList)) {
                                    //只需要把子科目加入其中一个就可以了
                                    //否则将会循环多次
                                    codeList.add(accountParentChildList.get(0).getCode());
                                    mapAccountUpdateParent(codeList, accountSetId, industryId, orgId, true);
                                }
                                accountMappingDao.mapStdAccountByCode(setOrg.getEnterpriseAccountSetID(), CommonConstants.EmptyStdCode,
                                        accountParent.getCode(), industryId, orgId, false, 0);
                            }
                        }
                    }
                }
            }
            //endregion

            OperationLogDto operationLogDto = new OperationLogDto();
            operationLogDto.setOperationContent(StringUtils.EMPTY);
            operationLogDto.setAction(OperationAction.New.value());
            operationLogDto.setOperationObject(org.getName() + "-" + accountSet.getName());
            operationLogDto.setOriginalState(StringUtils.EMPTY);
            operationLogDto.setUpdateState(StringUtils.EMPTY);
            operationLogDto.setModule(OperationModule.SubjectCorresponding.value());
            operationLogDto.setComment(StringUtils.EMPTY);
            operationLogDto.setLogType(OperateLogType.OperationLogSubject.value());
            operationLogService.addOperationLog(operationLogDto);

            return OperationResultDto.success();
        } else {
            return OperationResultDto.error(EnterpriseAccountSetOrgMsg.NoOrgSetOrOrgExist);
        }
    }

    @Transactional
    @Override
    public OperationResultDto mapAccount(AccountMapDto accountMapDto) {
        //region 获取相关的机构对象,标准科目对象, 账套对象
        Organization organization = organizationMapper.selectByPrimaryKey(accountMapDto.getOrgID());
        String industryID;
        if (organization == null) {
            return OperationResultDto.error(EnterpriseAccountConstant.OrgNotExist);
        }
        industryID = organization.getIndustryID();
        //通过该机构的行业ID和标准科目的Code获取相关的标准科目对象
        List<StandardAccount> tmpList = standardAccountDao.getByCodeAndIndustryId(accountMapDto.getStandardAccountCode(), industryID);
        if (CollectionUtils.isEmpty(tmpList)) {
            return OperationResultDto.error(EnterpriseAccountConstant.StdCodeIsNotExist);
        }
        StandardAccount stdAccount = tmpList.get(0);
        //通过机构的ID获取与之机构关联的账套对象
        //以下通过机构ID获取账套是错误的,因为一个机构存在多个账套,不知道用户选择的是哪个账套
        //var accountSet = this._dbContext.Set<EnterpriseAccountSetOrg>().Where(x => x.OrganizationID == organization.ID).FirstOrDefault();
        String accountSetID = accountMapDto.getAccountSetID();
        if (StringUtils.isBlank(accountSetID)) {
            return OperationResultDto.error(EnterpriseAccountConstant.AccountSetNotExist);
        }

        List<EnterpriseAccount> eaList = enterpriseAccountDao.getByEpAccountSetId(accountSetID);

        //获取账套信息
        EnterpriseAccountSet accountSet = enterpriseAccountSetMapper.selectByPrimaryKey(accountSetID);
        //endregion

        //region 手动对应当前及所有子科目

        for (String eAccountCode : accountMapDto.getEnterpriseAccountCodes()) {
            Optional<EnterpriseAccount> opEpAccount = eaList.stream().filter(x -> StringUtils.equals(x.getCode(), eAccountCode)).findFirst();
            EnterpriseAccount eAccount;
            if (opEpAccount.isPresent()) {
                eAccount = opEpAccount.get();
                //region 获取对应前旧对应关系所所对应的标准科目,为了记录日志
                List<AccountMapping> mappingList = accountMappingDao.getAccountMapping(eAccountCode, accountSetID, organization.getID());
                AccountMapping mapping;
                String originalCode = null;

                if (CollectionUtils.isNotEmpty(mappingList)) {
                    mapping = mappingList.get(0);
                    originalCode = mapping.getStandardAccountCode();
                }
                //endregion

                accountMappingDao.mapStdAccountByCode(accountSetID, stdAccount.getCode(), eAccount.getCode(), industryID,
                        organization.getID(), true, 0);

                //region 根据新的需求,需要将手动对应的记录记载下来,在下次自动对应的时候需要优先考虑
                AccountMappingManual manual = new AccountMappingManual();
                manual.setID(CommonUtils.getUUID());
                manual.setFullName(eAccount.getFullName());
                manual.setStandardCode(stdAccount.getCode());
                manual.setOrganizationID(organization.getID());
                manual.setEnterpriseAccountSetID(accountSetID);
                manual.setUpdateBy(authUserHelper.getCurrentAuditor());
                manual.setUpdateTime(new Date());
                addManualMappingRecord(manual);
                //endregion

                //1. 如果将标准科目对应到企业科目的父级,那么该企业科目的子级都对应到该标准科目
                updateManualMapChildAccount(eaList, eAccount, stdAccount, accountSetID, industryID, organization.getID());

                //region 添加日志
                OperationLogDto operationLogDto = new OperationLogDto();
                operationLogDto.setOperationContent(eAccount.getCode() + CommonConstants.DashSignSeparator + eAccount.getName());
                operationLogDto.setAction(OperationAction.ManualMapping.value());
                operationLogDto.setOperationObject(organization.getName() + "-" + accountSet.getName());
                operationLogDto.setOriginalState(StringUtils.isBlank(originalCode) ? StringUtils.EMPTY : originalCode +
                        CommonConstants.DashSignSeparator + stdAccount.getName());
                operationLogDto.setUpdateState(stdAccount.getCode() + CommonConstants.DashSignSeparator + stdAccount.getName());
                operationLogDto.setModule(OperationModule.SubjectCorresponding.value());
                operationLogDto.setComment(StringUtils.EMPTY);
                operationLogDto.setLogType(OperateLogType.OperationLogSubject.value());
                operationLogService.addOperationLog(operationLogDto);
                //endregion
            }
        }
        //endregion

        //region 手动对应当前的所有父级科目
        //清空ParentAccountMapResult
        this.mapParentAccountResult = Maps.newHashMap();
        mapAccountUpdateParent(Lists.newArrayList(accountMapDto.getEnterpriseAccountCodes()), accountSetID, industryID,
                organization.getID(), true);

        //endregion
        AccountMapDto mapDto = new AccountMapDto();
        mapDto.setParentAccountMappingResult(this.mapParentAccountResult);
        return OperationResultDto.success(mapDto);
    }

    @Override
    public OperationResultDto clearMap(String[] epAccountIDs, String orgId) {
        if (epAccountIDs != null && StringUtils.isNotBlank(orgId)) {
            boolean isToClearAllMapping = false;
            Organization organization = organizationMapper.selectByPrimaryKey(orgId);
            if (organization == null) {
                return OperationResultDto.error(EnterpriseAccountConstant.OrgNotExist);
            }
            String industryID = organization.getIndustryID();
            List<EnterpriseAccount> eaAllList = enterpriseAccountDao.getAll();
            List<String> enterpriseAccountIDs = Lists.newArrayList(epAccountIDs);
            List<EnterpriseAccount> enterpriseAccountList = eaAllList.stream().filter(x -> enterpriseAccountIDs.contains(x.getID())).collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(enterpriseAccountList)) {
                //获取该账套下有多少企业科目
                String enterprisetAccountSetId = enterpriseAccountList.get(0).getEnterpriseAccountSetID();
                long countOfEnterpriseAccount = eaAllList.stream().filter(x -> StringUtils.equals(x.getEnterpriseAccountSetID(),
                        enterprisetAccountSetId)).count();

                if (countOfEnterpriseAccount == enterpriseAccountList.size()) {
                    isToClearAllMapping = true;
                }
                accountMappingDao.clearMapping(enterpriseAccountList, industryID, orgId, isToClearAllMapping);
                //如果该账套下的企业科目和传进来需要取消的个数一样,说明是全部取消,没有必须要再去更新父级状态
                if (!isToClearAllMapping) {
                    //清空ParentAccountMapResult
                    this.mapParentAccountResult = Maps.newHashMap();
                    clearParentMapping(eaAllList, enterpriseAccountList, enterprisetAccountSetId, industryID, orgId);
                }
                //region 添加日志
                String enterpriseAccountID = enterpriseAccountIDs.get(0);
                //获取账套信息
                EnterpriseAccountSet accountSet = enterpriseAccountSetMapper.selectByPrimaryKey(enterprisetAccountSetId);
                //记载取消的企业科目
                String clearEACodeList = StringUtils.join(enterpriseAccountList.stream().map(x -> x.getCode())
                        .collect(Collectors.toList()), ",");

                OperationLogDto operationLogDto = new OperationLogDto();
                operationLogDto.setOperationContent(EnterpriseAccountConstant.SubjectCorresponding);
                operationLogDto.setAction(OperationAction.CancelMapping.value());
                operationLogDto.setOperationObject(accountSet != null ? organization.getName() + "-" + accountSet.getName()
                        : organization.getName());
                operationLogDto.setOriginalState(StringUtils.EMPTY);
                operationLogDto.setUpdateState(StringUtils.EMPTY);
                operationLogDto.setModule(OperationModule.SubjectCorresponding.value());
                operationLogDto.setComment(isToClearAllMapping ? StringUtils.EMPTY : clearEACodeList);
                operationLogDto.setLogType(OperateLogType.OperationLogSubject.value());
                operationLogService.addOperationLog(operationLogDto);
                //endregion

                AccountMapDto mapDto = new AccountMapDto();
                mapDto.setParentAccountMappingResult(this.mapParentAccountResult);
                return OperationResultDto.success(mapDto);
            }
        }
        return OperationResultDto.error(EnterpriseAccountConstant.NoAccountNeedClear);
    }

    private void clearParentMapping(List<EnterpriseAccount> eaAllList, List<EnterpriseAccount> eaClearList,
                                    String enterpriseAccountSetID, String industryID, String orgID) {
        for (EnterpriseAccount ea : eaClearList) {
            Optional<EnterpriseAccount> eaParentOp = eaAllList.stream().filter(x -> StringUtils.equals(x.getCode(),
                    ea.getParentCode()) && StringUtils.equals(x.getEnterpriseAccountSetID(), enterpriseAccountSetID)).findFirst();
            if (eaParentOp.isPresent()) {
                EnterpriseAccount eaParent = eaParentOp.get();
                //删除科目对应表里面的对应关系
                accountMappingDao.delMapping(eaParent.getCode(), enterpriseAccountSetID, orgID, industryID);
                //添加到list中为了更新UI界面
                addMapParentAccountResult(eaParent.getCode(), Lists.newArrayList(null, StringUtils.EMPTY));
                //删除父级以及更高层的对应关系
                clearParentMappingRecursion(eaAllList, eaParent, enterpriseAccountSetID, industryID, orgID);
            }
        }
    }

    private void clearParentMappingRecursion(List<EnterpriseAccount> eaAllList, EnterpriseAccount eaParent,
                                             String enterpriseAccountSetID, String industryID, String orgID) {
        if (StringUtils.isNotBlank(eaParent.getParentCode())) {
            Optional<EnterpriseAccount> parentAccountOp = eaAllList.stream().filter(x -> StringUtils.equals(x.getCode(),
                    eaParent.getParentCode()) && StringUtils.equals(x.getEnterpriseAccountSetID(), enterpriseAccountSetID)).findFirst();
            if (parentAccountOp.isPresent()) {
                EnterpriseAccount parentAccount = parentAccountOp.get();
                //删除科目对应表里面的对应关系
                accountMappingDao.delMapping(parentAccount.getCode(), enterpriseAccountSetID, orgID, industryID);
                //添加到list中为了更新UI界面
                addMapParentAccountResult(parentAccount.getCode(), Lists.newArrayList(null, StringUtils.EMPTY));
                clearParentMappingRecursion(eaAllList, parentAccount, enterpriseAccountSetID, industryID, orgID);
            }
        }
    }

    private void updateManualMapChildAccount(List<EnterpriseAccount> eaList, EnterpriseAccount eAccountCode, StandardAccount stdAccount,
                                             String accountSetID, String industryID, String orgID) {
        List<EnterpriseAccount> eAccount = eaList.stream().filter(x -> StringUtils.equals(x.getParentCode(), eAccountCode.getCode()))
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(eAccount)) {
            for (EnterpriseAccount ea : eAccount) {
                accountMappingDao.mapStdAccountByCode(accountSetID, stdAccount.getCode(), ea.getCode(), industryID, orgID,
                        true, 0);
                //region 根据新的需求,需要将手动对应的记录记载下来,在下次自动对应的时候需要优先考虑
                AccountMappingManual manual = new AccountMappingManual();
                manual.setID(CommonUtils.getUUID());
                manual.setFullName(ea.getFullName());
                manual.setStandardCode(stdAccount.getCode());
                manual.setOrganizationID(orgID);
                manual.setEnterpriseAccountSetID(accountSetID);
                manual.setIndustryID(industryID);
                manual.setUpdateBy(authUserHelper.getCurrentAuditor());
                manual.setUpdateTime(new Date());
                addManualMappingRecord(manual);
                //endregion
                updateManualMapChildAccount(eaList, ea, stdAccount, accountSetID, industryID, orgID);
            }
        }
    }

    public void addManualMappingRecord(AccountMappingManual manualMapping)
    {
        mappingManualDao.delMapping(manualMapping.getFullName(), manualMapping.getEnterpriseAccountSetID(),
                manualMapping.getOrganizationID(), manualMapping.getIndustryID());
        mappingManualMapper.insertSelective(manualMapping);
    }

    public List<EnterpriseAccountDto> getAllActiveAccounts(String orgID, String industryId, String accountSetId, Boolean isActive) {
        List<Map<String, Object>> list = enterpriseAccountDao.selectAccounts(industryId, accountSetId, orgID, EnterpriseAccountConstant.InvalidId,
                EnterpriseAccountConstant.InvalidId, EnterpriseAccountConstant.InvalidId, isActive);

        return list.stream().map(x -> {
            EnterpriseAccountDto dto = new EnterpriseAccountDto();
            dto.setCode(MapUtils.getString(x, "Code"));
            dto.setName(MapUtils.getString(x, "Name"));
            dto.setFullName(MapUtils.getString(x, "FullName"));
            dto.setParentCode(MapUtils.getString(x, "ParentCode"));
            dto.setAcctLevel(MapUtils.getInteger(x, "AcctLevel"));
            dto.setStdCode(MapUtils.getString(x, "StdCode"));
            dto.setIsLeaf(MapUtils.getShort(x, "IsLeaf") == EnterpriseAccountConstant.I_Yes);
            return dto;
        }).collect(Collectors.toList());
    }

    private Boolean mapAllChildrenRecursively(String orgID, String industryID, String accountSetId, String accountCode,
                                              String stdAccountCode, List<EnterpriseAccountDto> accounts, Boolean exceptionFlag) {
        List<String> enterpriseCodeList = Lists.newArrayList();
        boolean allChildrenMapped = true;
        List<EnterpriseAccountDto> children = accounts.stream().filter(x -> StringUtils.equals(x.getParentCode(), accountCode))
                .collect(Collectors.toList());

        for (EnterpriseAccountDto child : children) {
            if (child.getIsLeaf()) {
                if (StringUtils.isBlank(child.getStdCode())) {
                    accountMappingDao.mapStdAccountByCode(accountSetId, stdAccountCode, child.getCode(), industryID, orgID, false, 0);
                } else {
                    if (!StringUtils.equals(child.getStdCode(), stdAccountCode)) {
                        allChildrenMapped = false;

                        if (exceptionFlag) {
                            //只需要添加一次即可
                            enterpriseCodeList.add(child.getCode());
                        }
                    }
                }
            } else {
                allChildrenMapped = mapAllChildrenRecursively(orgID, industryID, accountSetId, child.getCode(),
                        stdAccountCode, accounts, false);
            }
        }

        //子科目全部对应时,父科目显示对应:1.子科目对应一致-子科目对应的标准科目;2.子科目对应不一致-0000
        if (allChildrenMapped) {
            accountMappingDao.mapStdAccountByCode(accountSetId, stdAccountCode, accountCode, industryID, orgID, false, 0);
        } else {
            accountMappingDao.mapStdAccountByCode(accountSetId, CommonConstants.EmptyStdCode, accountCode, industryID, orgID, false, 0);
        }

        if (exceptionFlag) {
            this.mapParentAccountResult = Maps.newHashMap();
            mapAccountUpdateParent(enterpriseCodeList, accountSetId, industryID, orgID, false);
        }

        //Update the mapping of parent account
        //var row = grdTarget.Rows.OfType<DataGridViewRow>()
        //    .Where(r => r.Cells["AccountCode"].Value.ToString().Trim() == accountCode).FirstOrDefault();
        //if (row != null)
        //{
        //    UpdateParentAccounts(row.Index, accountCode, false);
        //}

        return allChildrenMapped;
    }

    private void applyPriorityKeywords(List<EnterpriseAccountDto> allEpAccountDtoList, List<AccountMappingManual> allManualList,
                                       String accountSetID, String orgID, String industryID){
        List<AccountMappingManualDto> resultList;
        //1 账套机构行业都一样 (本身优先级别最高)
        List<AccountMappingManual> tmpManualList = allManualList.stream().filter(x -> StringUtils.equals(x.getEnterpriseAccountSetID(), accountSetID)
                && StringUtils.equals(x.getOrganizationID(), orgID) && StringUtils.equals(x.getIndustryID(), industryID)).collect(Collectors.toList());
        resultList = wrapPriority(tmpManualList, 1);

        //2 账套行业一样,机构不一样
        tmpManualList = allManualList.stream().filter(x -> StringUtils.equals(x.getEnterpriseAccountSetID(), accountSetID)
                && !StringUtils.equals(x.getOrganizationID(), orgID) && StringUtils.equals(x.getIndustryID(), industryID)).collect(Collectors.toList());
        resultList = getManualMappingResult(resultList, wrapPriority(tmpManualList, 2));

        //3 账套不一样,机构和行业都一样
        tmpManualList = allManualList.stream().filter(x -> !StringUtils.equals(x.getEnterpriseAccountSetID(), accountSetID)
                && StringUtils.equals(x.getOrganizationID(), orgID) && StringUtils.equals(x.getIndustryID(), industryID)).collect(Collectors.toList());
        resultList = getManualMappingResult(resultList, wrapPriority(tmpManualList, 3));

        //4 账套机构一样,行业不一样
        tmpManualList = allManualList.stream().filter(x -> StringUtils.equals(x.getEnterpriseAccountSetID(), accountSetID)
                && StringUtils.equals(x.getOrganizationID(), orgID) && !StringUtils.equals(x.getIndustryID(), industryID)).collect(Collectors.toList());
        resultList = getManualMappingResult(resultList, wrapPriority(tmpManualList, 4));

        //5 机构一样,账套行业不一样
        tmpManualList = allManualList.stream().filter(x -> !StringUtils.equals(x.getEnterpriseAccountSetID(), accountSetID)
                && StringUtils.equals(x.getOrganizationID(), orgID) && !StringUtils.equals(x.getIndustryID(), industryID)).collect(Collectors.toList());
        resultList = getManualMappingResult(resultList, wrapPriority(tmpManualList, 5));

        //6 账套机构不一样,行业一样
        tmpManualList = allManualList.stream().filter(x -> !StringUtils.equals(x.getEnterpriseAccountSetID(), accountSetID)
                && !StringUtils.equals(x.getOrganizationID(), orgID) && StringUtils.equals(x.getIndustryID(), industryID)).collect(Collectors.toList());
        resultList = getManualMappingResult(resultList, wrapPriority(tmpManualList, 6));

        //7 账套一样,机构行业都不一样
        tmpManualList = allManualList.stream().filter(x -> StringUtils.equals(x.getEnterpriseAccountSetID(), accountSetID)
                && !StringUtils.equals(x.getOrganizationID(), orgID) && !StringUtils.equals(x.getIndustryID(), industryID)).collect(Collectors.toList());
        resultList = getManualMappingResult(resultList, wrapPriority(tmpManualList, 7));

        //8 账套机构行业都不一样
        tmpManualList = allManualList.stream().filter(x -> !StringUtils.equals(x.getEnterpriseAccountSetID(), accountSetID)
                && !StringUtils.equals(x.getOrganizationID(), orgID) && !StringUtils.equals(x.getIndustryID(), industryID)).collect(Collectors.toList());
        resultList = getManualMappingResult(resultList, wrapPriority(tmpManualList, 8));

        List<AccountMapping> mappingList = Lists.newArrayList();
        resultList.stream().forEach(x->{
            allEpAccountDtoList.stream().filter(EnterpriseAccountDto::getIsLeaf).forEach(y->{
                if (StringUtils.equals(x.getFullName(),y.getFullName())){
                    AccountMapping tmp = new AccountMapping();
                    tmp.setID(CommonUtils.getUUID());
                    tmp.setEnterpriseAccountCode(y.getCode());
                    tmp.setStandardAccountCode(x.getStandardCode());
                    tmp.setOrganizationID(orgID);
                    tmp.setIndustryID(industryID);
                    mappingList.add(tmp);
                }
            });
        });

        //先删除
        List<AccountMapping> filterMappingResult = mappingList.stream().filter(x -> StringUtils.isNotBlank(x.getEnterpriseAccountCode()))
                .collect(Collectors.toList());
        List<String> filterEACodeList = filterMappingResult.stream().map(AccountMapping::getEnterpriseAccountCode).collect(Collectors.toList());

        accountMappingDao.delByEpAccountCodeList(filterEACodeList);

        filterMappingResult.stream().forEach(x -> accountMappingMapper.insertSelective(x));

    }

    private List<AccountMappingManualDto> getManualMappingResult(List<AccountMappingManualDto> priorityList,
                                                                 List<AccountMappingManualDto> lowerPriorityList) {
        List<AccountMappingManualDto> originalMapList = new ArrayList<>(priorityList);

        List<String> list1 = priorityList.stream().map(AccountMappingManualDto::getFullName).collect(Collectors.toList());
        List<String> list2 = lowerPriorityList.stream().map(AccountMappingManualDto::getFullName).collect(Collectors.toList());
        List<String> intersectedList = list1.stream().filter(list2::contains).collect(Collectors.toList());
        List<AccountMappingManualDto> addedList = lowerPriorityList.stream().filter(x -> list2.stream()
                .filter(y -> !intersectedList.contains(y)).collect(Collectors.toList()).contains(x.getFullName()))
                .collect(Collectors.toList());

        originalMapList.addAll(addedList);

        return originalMapList;
    }

    private List<AccountMappingManualDto> wrapPriority(List<AccountMappingManual> manualList, int priority) {
        return manualList.stream().collect(Collectors.groupingBy(AccountMappingManual::getFullName))
                .entrySet().stream().map(x -> {
                    AccountMappingManualDto dto = new AccountMappingManualDto();
                    AccountMappingManual manual = x.getValue().stream().sorted((m1, m2) -> m2.getUpdateTime()
                            .compareTo(m1.getUpdateTime())).findFirst().get();
                    CommonUtils.copyProperties(manual, dto);
                    dto.setPriority(priority);
                    return dto;
                }).collect(Collectors.toList());
    }

    private void formatEpAccountDtoTree(List<EnterpriseAccountDto> rootList, List<EnterpriseAccountDto> allList,
                                        List<EnterpriseAccountDto> result) {
        if (CollectionUtils.isEmpty(rootList)) {
            return;
        }
        int level = rootList.get(0).getTreeLevel() + 1;
        rootList.forEach(item -> {
            result.add(item);
            List<EnterpriseAccountDto> subList = allList.stream().filter(x -> StringUtils.equals(x.getParentCode(), item.getCode()))
                    .map(x -> {
                        x.setTreeLevel(level);
                        x.setParentName(item.getName());
                        x.setParentFullName(item.getFullName());
                        return x;
                    }).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(subList)) {
                result.addAll(subList);
                formatEpAccountDtoTree(subList, allList, result);
            }
        });
    }

    private EnterpriseAccountSetDto toAccountSetDto(EnterpriseAccountSet accountSet) {
        EnterpriseAccountSetDto dto = new EnterpriseAccountSetDto();
        return CommonUtils.copyProperties(accountSet, dto);
    }

    /**
     * Validates the enterprise account list.
     * @param epAccountList
     * @return The validate list
     */
    private List<ValidateInfoDto> validateEnterpriseAccountList(List<EnterpriseAccountDto> epAccountList) {
        List<ValidateInfoDto> validateInfoDtolist = new ArrayList<>();
        validateInfoDtolist.add(this.getRepeatValidate(epAccountList));
        validateInfoDtolist.add(this.getEmptyNameValidate(epAccountList));
        validateInfoDtolist.add(this.getDirectionValidate(epAccountList));
        validateInfoDtolist.add(this.getAcctPropNullValidate(epAccountList));
        validateInfoDtolist.add(this.getAcctPropValidate(epAccountList));
        validateInfoDtolist.add(this.getNoParentValidate(epAccountList));
        
        return validateInfoDtolist.stream()
                .filter(validateInfo -> validateInfo.getInValidateCodeList()!=null && !validateInfo.getInValidateCodeList().isEmpty())
                .collect(Collectors.toList());
        
    }
    
    /**
     * Validates if there is any duplication account code in the list
     * @param list
     * @return ValidateInfoDto
     */
    private ValidateInfoDto getRepeatValidate(List<EnterpriseAccountDto> epAccountList) {
        
        ValidateInfoDto validateInfoDto = new ValidateInfoDto();
        validateInfoDto.setType(EnterpriseAccountMessage.EnterpriceAccountRepeat);
        
        List<String> distinctCodeList = epAccountList.stream()
                .map(epAccount -> epAccount.getCode()).distinct().collect(Collectors.toList());
        
        for(String code: distinctCodeList) {
            List<EnterpriseAccountDto> accountsWithSameCode = epAccountList.stream()
                    .filter(epAccount -> code.equals(epAccount.getCode())).collect(Collectors.toList());
            if(accountsWithSameCode!=null && accountsWithSameCode.size()>1) {
                validateInfoDto.addInValidateCode(code);
            }
        }
        return validateInfoDto;
    }
    
    /**
     * Validates if there is any account with wrong direction value 
     * @param epAccountList
     * @return ValidateInfoDto
     */
    private ValidateInfoDto getDirectionValidate(List<EnterpriseAccountDto> epAccountList) {
        
        ValidateInfoDto validateInfoDto = new ValidateInfoDto();
        validateInfoDto.setType(EnterpriseAccountMessage.DirectionFormatError);
        
        List<String> inValidateCodeList = epAccountList.stream()
                .filter(epAccount -> 
                    !CommonConstants.CreditDirectionValue.equals(epAccount.getDirection()) && !CommonConstants.DebitDirectionValue.equals(epAccount.getDirection()))
                .map(epAccount -> epAccount.getCode())
                .distinct().collect(Collectors.toList());
        validateInfoDto.setInValidateCodeList(inValidateCodeList);
        
        return validateInfoDto;
    }
    
    /**
     * Validates if there is any account with wrong accprop value
     * @param epAccountList
     * @return ValidateInfoDto
     */
    private ValidateInfoDto getAcctPropValidate(List<EnterpriseAccountDto> epAccountList) {
     
        ValidateInfoDto validateInfoDto = new ValidateInfoDto();
        validateInfoDto.setType(EnterpriseAccountMessage.AcctPropFormatError);
        
        List<String> inValidateCodeList = epAccountList.stream()
                .filter(epAccount -> 
                   epAccount.getAcctProp()!=null && (epAccount.getAcctProp() > EnterpriseAccountConstant.MaxAcctPropValue || (epAccount.getAcctProp() < EnterpriseAccountConstant.MinAcctPropValue && epAccount.getAcctProp() != EnterpriseAccountConstant.SpecialAcctPropValue)))
                .map(epAccount -> epAccount.getCode())
                .distinct().collect(Collectors.toList());
        validateInfoDto.setInValidateCodeList(inValidateCodeList);
        
        return validateInfoDto;
    }
    
    /**
     * Validates if there is any account with null accprop value
     * @param epAccountList
     * @return ValidateInfoDto
     */
    private ValidateInfoDto getAcctPropNullValidate(List<EnterpriseAccountDto> epAccountList) {
        
        ValidateInfoDto validateInfoDto = new ValidateInfoDto();
        validateInfoDto.setType(EnterpriseAccountMessage.AcctPropNullError);
        
        List<String> inValidateCodeList = epAccountList.stream()
                .filter(epAccount -> 
                   epAccount.getAcctProp()==null)
                .map(epAccount -> epAccount.getCode())
                .distinct().collect(Collectors.toList());
        validateInfoDto.setInValidateCodeList(inValidateCodeList);
        
        return validateInfoDto;
    }
    
    /**
     * Validates if there is any account with empty name
     * @param epAccountList
     * @return ValidateInfoDto
     */
    private ValidateInfoDto getEmptyNameValidate(List<EnterpriseAccountDto> epAccountList) {
        
        ValidateInfoDto validateInfoDto = new ValidateInfoDto();
        validateInfoDto.setType(EnterpriseAccountMessage.EnterpriseAccountNameEmpty);
        
        List<String> inValidateCodeList = epAccountList.stream()
                .filter(epAccount -> epAccount.getName() == null || epAccount.getName().equals(""))
                .map(epAccount -> epAccount.getCode())
                .distinct().collect(Collectors.toList());
        validateInfoDto.setInValidateCodeList(inValidateCodeList);
        
        return validateInfoDto;
    }
    
    /**
     * Validates if there is any account with empty name
     * @param epAccountList
     * @return ValidateInfoDto
     */
    private ValidateInfoDto getNoParentValidate(List<EnterpriseAccountDto> epAccountList) {
        
        ValidateInfoDto validateInfoDto = new ValidateInfoDto();
        validateInfoDto.setType(EnterpriseAccountMessage.NoParentCode);
        
        List<EnterpriseAccountDto> accountsWithParent = epAccountList.stream().filter(epAccount -> epAccount.getParentCode()!=null && !epAccount.getParentCode().equals(""))
                .collect(Collectors.toList());
        
        for (EnterpriseAccountDto accountWithParent: accountsWithParent) {
            boolean parentExist = epAccountList.stream()
                .anyMatch(epAccount -> epAccount.getCode().equals(accountWithParent.getParentCode()));
            if(!parentExist) {
                validateInfoDto.addInValidateCode(accountWithParent.getCode());
            }
        }
        return validateInfoDto;
        
    }
    
    
    /**
     * Gets the same enterprise account list.
     * @param enterpriseAccountDto
     * @return
     */
    private List<EnterpriseAccountDto> getSameEnterpriseAccountList(EnterpriseAccountDto enterpriseAccountDto){
        
        if (enterpriseAccountDto == null) {
            return null;
        }
        
        EnterpriseAccountExample enterpriseAccountExample = new EnterpriseAccountExample();
        EnterpriseAccountExample.Criteria criteria = enterpriseAccountExample.createCriteria();
        if(enterpriseAccountDto.getID()!=null && !enterpriseAccountDto.getID().isEmpty()) {
            criteria.andIDNotEqualTo(enterpriseAccountDto.getID());
        }
        criteria.andEnterpriseAccountSetIDEqualTo(enterpriseAccountDto.getEnterpriseAccountSetID())
            .andCodeEqualTo(enterpriseAccountDto.getCode())
            .andIsActiveEqualTo(CommonConstants.ACTIVE_STATUS);
        List<EnterpriseAccount> epAccountsWithSameCode = enterpriseAccountMapper.selectByExample(enterpriseAccountExample);
        //没有重复项
        if(epAccountsWithSameCode == null || epAccountsWithSameCode.isEmpty()) {
            return null;
        }
        
        //有重复项
        List<EnterpriseAccountDto> sameEnterpriseAccountDtoList = new ArrayList<>();
        for(EnterpriseAccount enterpriseAccount : epAccountsWithSameCode) {
            enterpriseAccountExample = new EnterpriseAccountExample();
            criteria = enterpriseAccountExample.createCriteria();
            if(enterpriseAccount.getParentCode()!=null && !enterpriseAccount.getParentCode().isEmpty()) {
                criteria.andCodeEqualTo(enterpriseAccount.getParentCode());
            }
            criteria.andRuleTypeEqualTo(2)    
                .andIsActiveEqualTo(CommonConstants.ACTIVE_STATUS);
            List<EnterpriseAccount> epAccountsParent = enterpriseAccountMapper.selectByExample(enterpriseAccountExample);
            if(epAccountsParent!=null&&!epAccountsParent.isEmpty()) {
                epAccountsParent.stream().forEach(epAccountParent -> {
                    EnterpriseAccountDto epAccountDto = new EnterpriseAccountDto();
                    CommonUtils.copyProperties(enterpriseAccount, epAccountDto);
                    epAccountDto.setParentName(epAccountParent.getName());
                    epAccountDto.setParentFullName(epAccountParent.getFullName());
                    epAccountDto.setSubStdAccounts(new ArrayList<>());
                    sameEnterpriseAccountDtoList.add(epAccountDto);
                });
            }
            else {
                EnterpriseAccountDto epAccountDto = new EnterpriseAccountDto();
                CommonUtils.copyProperties(enterpriseAccount, epAccountDto);
                epAccountDto.setParentName("");
                epAccountDto.setParentFullName("");
                epAccountDto.setSubStdAccounts(new ArrayList<>());
                sameEnterpriseAccountDtoList.add(epAccountDto);
            }
        }
        return sameEnterpriseAccountDtoList;
    }
    
    /**
     * Sets the parent is not leaf.
     * @param parentCode - The parent code
     * @param enterpriseAccountSetID - The enterprise account set identifier
     */
    private void setParentIsNotLeaf(String parentCode, String enterpriseAccountSetID) {
        
        // no parent, do nothing
        if(parentCode == null || parentCode.isEmpty()) {
            return;
        }
        
        EnterpriseAccountExample example = new EnterpriseAccountExample();
        example.createCriteria().andCodeEqualTo(parentCode).andEnterpriseAccountSetIDEqualTo(enterpriseAccountSetID);
        List<EnterpriseAccount> parentNodes = enterpriseAccountMapper.selectByExample(example);
        if(parentNodes==null || parentNodes.isEmpty()) {
            return;
        }
        EnterpriseAccount parentNode = parentNodes.get(0);
        if(parentNode!=null && parentNode.getIsLeaf().equals(CommonConstants.IsLeaf)) {
            //save enterpriseAccount
            EnterpriseAccount parentNodeOriginal = new EnterpriseAccount();
            CommonUtils.copyProperties(parentNode, parentNodeOriginal);
            parentNode.setIsLeaf(CommonConstants.IsNotLeaf);
            enterpriseAccountMapper.updateByPrimaryKey(parentNode);
            //save operational log
            UpdateLogParams updateLogParams = new UpdateLogParams();
            updateLogParams.setOriginalState(parentNodeOriginal);
            updateLogParams.setUpdateState(parentNode);
            updateLogParams.setOperationModule(OperationModule.BasicDataEnterpriceAccount.value());
            updateLogParams.setOperationUser(authUserHelper.getCurrentAuditor());
            updateLogParams.setComment(LogMessage.EnterpriceAccountImportUpdate);
            updateLogParams.setOperationObject(parentNodeOriginal.getName());
            updateLogParams.setOperationContent("operation content");
            updateLogParams.setOperateLogType(OperateLogType.OperationLogEnterPrise.value());
            updateLogParams.setOperationAction(OperationAction.Update.value());
            operationLogService.updateDataAddLog(updateLogParams);
        }
    }
    
    /**
     * Sets the parent leaf.
     * @param parentCode - The parentcode
     * @param enterpriseAccountSetID 
     * @param currentEpAccountID - Current enterprise account ID
     */
    private void setParentLeaf(String parentCode, String enterpriseAccountSetID, String currentEpAccountID) {
        // no parent, do nothing
        if(parentCode == null || parentCode.isEmpty()) {
            return;
        }
        
        EnterpriseAccount parentNodeEntity = getEnterpriseAccount(parentCode, enterpriseAccountSetID);
        if(parentNodeEntity == null) {
            return;
        }
        
        //copy parentNodeEntity
        EnterpriseAccount parentNodeOriginal = new EnterpriseAccount();
        CommonUtils.copyProperties(parentNodeEntity, parentNodeOriginal);
        
        //get other children nodes of this parent
        EnterpriseAccountExample example = new EnterpriseAccountExample();
        example.createCriteria()
            .andParentCodeEqualTo(parentNodeEntity.getCode())
            .andIDNotEqualTo(currentEpAccountID)
            .andEnterpriseAccountSetIDEqualTo(enterpriseAccountSetID);
        List<EnterpriseAccount> childrenAccountsOfparentNode = enterpriseAccountMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(childrenAccountsOfparentNode)) {
            // no sub node list, set is the leaf node
            parentNodeEntity.setIsLeaf(CommonConstants.IsLeaf);
            enterpriseAccountMapper.updateByPrimaryKey(parentNodeEntity);
            
            //operation log
            UpdateLogParams updateLogParams = new UpdateLogParams();
            updateLogParams.setOriginalState(parentNodeOriginal);
            updateLogParams.setUpdateState(parentNodeEntity);
            updateLogParams.setOperationModule(OperationModule.BasicDataEnterpriceAccount.value());
            updateLogParams.setOperationUser(authUserHelper.getCurrentAuditor());
            updateLogParams.setComment(LogMessage.EnterpriceAccountImportUpdate);
            updateLogParams.setOperationObject(parentNodeOriginal.getName());
            updateLogParams.setOperationContent("operation content");
            updateLogParams.setOperateLogType(OperateLogType.OperationLogEnterPrise.value());
            updateLogParams.setOperationAction(OperationAction.Update.value());
            operationLogService.updateDataAddLog(updateLogParams);
        }
    }
    
    /**
     * 通过Parent企业科目对象获取该ParentCode下面的所有子企业科目
     * @param parentCode - Parent企业科目代码
     * @param accountSetId - 企业账套ID
     * @param industryID - 行业ID
     * @param orgID - 机构ID
     * @return
     */
    private List<EnterpriseAccount> getMappingResultByParentCode(String parentCode, String accountSetID, String industryID, String orgID) {
        return customAccountMapper.getMappingResult(accountSetID, industryID, orgID, parentCode);
    }
    
    private void addMapParentAccountResult(String key, List<String> value)
    {
        if (!mapParentAccountResult.containsKey(key))
        {
            this.mapParentAccountResult.put(key, value);
        }
    }
    
    private String getConvertedIndustryID(String industryID)
    {
        if (industryID != null && industryID.equals(IndustryConstant.RealEstateID))
        {
            return industryID;
        }
        return IndustryConstant.GeneralIndustryID;
    }
    
    private String getEnterpriseAccountInfo(EnterpriseAccount enterpriseAccount)
    {
        String str = "";
        if (enterpriseAccount.getAcctProp()!=null && enterpriseAccount.getAcctProp() < EnterpriseAccountConstant.acctPropLogList.size()) {
            if (enterpriseAccount.getAcctProp() <= -1) {
                str = EnterpriseAccountConstant.acctPropLogList.get(0);
            }
            else {
                str = EnterpriseAccountConstant.acctPropLogList.get(enterpriseAccount.getAcctProp());
            }
        }
        return enterpriseAccount.getCode() + " " 
            + enterpriseAccount.getName() + " " + str + " " 
            + EnterpriseAccountConstant.directionLogMap.get(enterpriseAccount.getDirection());
    }
    
    private void enableEnterpriseAccountSet(String enterpriseAccountSetID) {
        
        EnterpriseAccountSet enterpriseAccountSet = enterpriseAccountSetMapper.selectByPrimaryKey(enterpriseAccountSetID);
        if(enterpriseAccountSet.getIsActive()) {
            return;
        }
        
        EnterpriseAccountExample example = new EnterpriseAccountExample();
        example.createCriteria().andEnterpriseAccountSetIDEqualTo(enterpriseAccountSetID);
        List<EnterpriseAccount> enterpriseAccountList = enterpriseAccountMapper.selectByExample(example);
        
        if (CollectionUtils.isEmpty(enterpriseAccountList)) {
            return;
        }
        
        List<EnterpriseAccountDto> enterpriseAccountDtoList = new ArrayList<>();
        enterpriseAccountList.stream().forEach(sa -> {
            EnterpriseAccountDto enterpriseAccountDto = new EnterpriseAccountDto();
            CommonUtils.copyProperties(sa, enterpriseAccountDto);
            enterpriseAccountDtoList.add(enterpriseAccountDto);
        });
        List<ValidateInfoDto> validateInfoDtoList = validateEnterpriseAccountList(enterpriseAccountDtoList);
        boolean anyValidationErrorExist = validateInfoDtoList.stream().filter(sa -> !CollectionUtils.isEmpty(sa.getInValidateCodeList())).findAny().isPresent();
        if(!anyValidationErrorExist) {
            if(!enterpriseAccountSet.getIsActive()) {
                enterpriseAccountSet.setIsActive(CommonConstants.ACTIVE_STATUS);
                enterpriseAccountSetMapper.updateByPrimaryKey(enterpriseAccountSet);
            }
        }
            
    }
    
    
    /* (non-Javadoc)
     * @see pwc.taxtech.atms.service.EnterpriseAccountService#validateImportEnterpriseAccount(java.io.InputStream, java.lang.String)
     */
    @Override
    public OperationResultDto<List<EnterpriseAccountDto>> validateImportEnterpriseAccount(String filePath) {
        
        //validate header
        InputStream savedInputStream = Files.findFileAsStream(filePath);
        Map<String, Integer> headerMap = fileService.readExcelHeaderAndClose(savedInputStream);
        List<String> standardHeader = Arrays.asList(
                EnterpriseAccountConstant.Code, 
                EnterpriseAccountConstant.Name, 
                EnterpriseAccountConstant.ParentCode, 
                EnterpriseAccountConstant.Direction, 
                EnterpriseAccountConstant.AcctProp);
        boolean hasParentCode = true;
        for(String header: standardHeader) {
            Integer index = headerMap.get(header);
            if(index == null) {
                if(header.equals(EnterpriseAccountConstant.ParentCode)) {
                    hasParentCode = false;
                    continue;
                }
                return new OperationResultDto<>(false, EnterpriseAccountMessage.EnterpriceAccountImportDataFormatError);
            }
        }
        
        //read excel data
        savedInputStream = Files.findFileAsStream(filePath);
        Collection<Map> mapCollection = fileService.readExcelAndClose(savedInputStream);
        
        //nothing to import
        if(mapCollection==null || CollectionUtils.isEmpty(mapCollection)) {
            return new OperationResultDto<>(true);
        }
        
        //validate data
        List<EnterpriseAccountDto> importData = new ArrayList<>();
        for (Map map: mapCollection) {
            EnterpriseAccountDto enterpriseAccountDto = new EnterpriseAccountDto();
            
            //direction
            String direction = map.get(EnterpriseAccountConstant.Direction)==null ? null: map.get(EnterpriseAccountConstant.Direction).toString();
            if (direction == null || direction.trim().isEmpty()) {
                direction = CommonConstants.DebitDirection;
            }
            try {
                enterpriseAccountDto.setDirection(Integer.valueOf(direction));
            }
            catch (NumberFormatException e) {
                return new OperationResultDto<>(false, EnterpriseAccountMessage.DirectionFormatError);
            }
            
            //accprop 
            String acctProp = map.get(EnterpriseAccountConstant.AcctProp)==null ? null:map.get(EnterpriseAccountConstant.AcctProp).toString();
            if(acctProp == null || acctProp.trim().isEmpty()) {
                acctProp = "-1";
            }
            try {
                enterpriseAccountDto.setAcctProp(Integer.valueOf(acctProp));
            }
            catch (NumberFormatException e) {
                return new OperationResultDto<>(false, EnterpriseAccountMessage.AcctPropFormatError);
            }
            
            //code
            String code = map.get(EnterpriseAccountConstant.Code)==null ? null:map.get(EnterpriseAccountConstant.Code).toString();
            if(code == null || code.trim().isEmpty()) {
                return new OperationResultDto<>(false, EnterpriseAccountMessage.CodeEmpty);
            }
            if(code.length()>EnterpriseAccountConstant.CodeMaxLength) {
                return new OperationResultDto<>(false, EnterpriseAccountMessage.CodeMaxLength);
            }
            enterpriseAccountDto.setCode(code);
            
            //name
            String name = map.get(EnterpriseAccountConstant.Name)==null ? null:map.get(EnterpriseAccountConstant.Name).toString();
            if(name==null || name.trim().isEmpty()) {
                name = "";
            }
            if(name.length()>EnterpriseAccountConstant.NameMaxLength) {
                return new OperationResultDto<>(false, EnterpriseAccountMessage.NameMaxLength);
            }
            enterpriseAccountDto.setName(name);
            
            //parentCode
            String parentCode = "";
            if(hasParentCode) {
                parentCode = map.get(EnterpriseAccountConstant.ParentCode)==null ? null:map.get(EnterpriseAccountConstant.ParentCode).toString();
            }
            if(enterpriseAccountDto.getCode().equals(parentCode)) {
                parentCode = "";
            }
            enterpriseAccountDto.setParentCode(parentCode);
        
            importData.add(enterpriseAccountDto);
        }
        OperationResultDto<List<EnterpriseAccountDto>> result = new OperationResultDto<>(true); 
        result.setData(importData);
        return result;
    }
    
    private OperationResultDto<?> importDataProcess(List<EnterpriseAccountDto> importData, String enterpriseAccountSetID, boolean isImportAppend) {
        
        //nothing to import
        if(CollectionUtils.isEmpty(importData) && isImportAppend) {
            return OperationResultDto.success();
        }
        // transfrom data
        List<EnterpriseAccount> importEntityList = transform(importData, enterpriseAccountSetID);
        
        //disable EnterpriseAccountSet
        EnterpriseAccountSet enterpriseAccountSet = enterpriseAccountSetMapper.selectByPrimaryKey(enterpriseAccountSetID);
        if(enterpriseAccountSet.getIsActive()) {
            enterpriseAccountSet.setIsActive(CommonConstants.DEACTIVE_STATUS);
            enterpriseAccountSetMapper.updateByPrimaryKey(enterpriseAccountSet);
        }

        //import
        //如覆盖导入先批量删除
        if(!isImportAppend) {
            EnterpriseAccountExample example = new EnterpriseAccountExample();
            example.createCriteria().andEnterpriseAccountSetIDEqualTo(enterpriseAccountSetID);
            enterpriseAccountMapper.deleteByExample(example);
        }
        //导入
        for(EnterpriseAccount importEntity: importEntityList) {
            enterpriseAccountMapper.insertSelective(importEntity);
        }
        
        //enable EnterpriseAccountSet
        enableEnterpriseAccountSet(enterpriseAccountSetID);
        
        return OperationResultDto.success();
        
    }
    
    /**
     * @param importData
     * @param enterpriseAccountSetID
     * @return
     */
    private List<EnterpriseAccount> transform(List<EnterpriseAccountDto> importData, String enterpriseAccountSetID) {
        
        if(CollectionUtils.isEmpty(importData)) {
            return new ArrayList<>();
        }
        importData.stream().forEach(account -> {
            account.setID(CommonUtils.getUUID());
            account.setEnterpriseAccountSetID(enterpriseAccountSetID);
            account.setIsActive(true);
            account.setCreateTime(new Date());
            account.setUpdateTime(new Date());
            String userId = authUserHelper.getCurrentUserID();
            account.setCreatorID(userId);
            account.setUpdatorID(userId);
        });
        
        //set parent code, 
        List<String> validateCodeList = importData.stream().map(sa -> sa.getCode()).collect(Collectors.toList());
        for (EnterpriseAccountDto enterpriseAccountDto: importData) {
            if(enterpriseAccountDto.getParentCode()==null || enterpriseAccountDto.getParentCode().isEmpty()) {
                enterpriseAccountDto.setParentCode(getMatchParentCode(enterpriseAccountDto.getCode(), validateCodeList));
            }
        }
        
        //set acct level,is leaf
        List<String> parentCodeList = importData.stream().filter(sa -> sa.getParentCode()!=null && !sa.getParentCode().isEmpty())
                .map(sa -> sa.getParentCode()).collect(Collectors.toList());
        for (EnterpriseAccountDto enterpriseAccountDto: importData) {
            setAcctLevel(enterpriseAccountDto, importData);
            if(CollectionUtils.isEmpty(parentCodeList)) {
                enterpriseAccountDto.setIsLeaf(true);
            }
            else {
                if(parentCodeList.contains(enterpriseAccountDto.getCode())) {
                    enterpriseAccountDto.setIsLeaf(false);
                }
                else {
                    enterpriseAccountDto.setIsLeaf(true);
                }
            }
        }
        
        //populate entity list
        List<EnterpriseAccount> enterpriseAccountList = new ArrayList<>();
        importData.stream().forEach(enterpriseAccountDto -> {
            EnterpriseAccount enterpriseAccount = new EnterpriseAccount();
            CommonUtils.copyProperties(enterpriseAccountDto, enterpriseAccount);
            enterpriseAccount.setRuleType(2);
            enterpriseAccountList.add(enterpriseAccount);
        });
        
        return enterpriseAccountList;
    }
    
    
    /**
     * Get parent Code from existing validated code list
     * @param code
     * @param validateCodeList
     * @return parent code
     */
    private String getMatchParentCode(String code, List<String> validateCodeList) {
        
        for(int i = code.length()-1; i>=0; i--) {
            String temp = code.substring(0, i);
            List<String> matchList = validateCodeList.stream().filter(vCode -> vCode.equals(temp)).collect(Collectors.toList());
            if(matchList!=null && matchList.size()==1) {
                return temp;
            }
        }
        return null;
    }
    
    /**
     * Sets the acct level.
     * @param current - The current
     * @param validateList - The validate list
     */
    private void setAcctLevel(EnterpriseAccountDto currentDto, List<EnterpriseAccountDto> validateDtoList) {
        
        if(currentDto.getParentCode()==null || currentDto.getParentCode().isEmpty()) {
            currentDto.setAcctLevel(1);
            currentDto.setFullName(currentDto.getName());
            return;
        }
        EnterpriseAccountDto parentDto = null;
        Optional<EnterpriseAccountDto> ifparentDtoExist = validateDtoList.stream()
                .filter(sa -> sa.getCode().equals(currentDto.getParentCode())).findAny();
        if(ifparentDtoExist.isPresent()) {
            parentDto = ifparentDtoExist.get();
        }
        if(parentDto!=null) {
            if(parentDto.getAcctLevel()==null) {
                setAcctLevel(parentDto, validateDtoList);
            }
            currentDto.setAcctLevel(parentDto.getAcctLevel()+1);
            
            if(currentDto.getName()!=null && !currentDto.getName().isEmpty() 
                    && !currentDto.getName().contains(parentDto.getFullName() + EnterpriseAccountConstant.FullNameSeparator)) {
                currentDto.setFullName(parentDto.getFullName() + EnterpriseAccountConstant.FullNameSeparator + currentDto.getName());
            }
            else {
                currentDto.setFullName(currentDto.getName());
            }
        }
        else {
            currentDto.setFullName(currentDto.getName());
        }
    }
    
}