package pwc.taxtech.atms.service.impl;

import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.format.DateTimeFormat;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.Assert;
import pwc.taxtech.atms.common.CommonConstants;
import pwc.taxtech.atms.common.CommonUtils;
import pwc.taxtech.atms.common.OperateLogType;
import pwc.taxtech.atms.common.OperationAction;
import pwc.taxtech.atms.common.OperationModule;
import pwc.taxtech.atms.common.ServiceTypeEnum;
import pwc.taxtech.atms.common.VatTaxPayerTypeEnum;
import pwc.taxtech.atms.common.message.EnterpriseAccountSetOrgMessage;
import pwc.taxtech.atms.common.message.LogMessage;
import pwc.taxtech.atms.common.message.OrganizationMessage;
import pwc.taxtech.atms.constant.AreaConstant;
import pwc.taxtech.atms.constant.DimensionConstant;
import pwc.taxtech.atms.constant.LevelConstant;
import pwc.taxtech.atms.constant.OrganizationConstant;
import pwc.taxtech.atms.dao.*;
import pwc.taxtech.atms.dpo.*;
import pwc.taxtech.atms.dto.AreaOrganizationStatistics;
import pwc.taxtech.atms.dto.AreaStatistics;
import pwc.taxtech.atms.dto.IndustryDto;
import pwc.taxtech.atms.dto.OperationLogDto;
import pwc.taxtech.atms.dto.OperationResultDto;
import pwc.taxtech.atms.dto.OrganizationStatistics;
import pwc.taxtech.atms.dto.OrganizationValidateDto;
import pwc.taxtech.atms.dto.UpdateLogParams;
import pwc.taxtech.atms.dto.dimension.AttributeTypeEnum;
import pwc.taxtech.atms.dto.dimension.DimensinTypeOrgDto;
import pwc.taxtech.atms.dto.dimension.DimensionOrgDto;
import pwc.taxtech.atms.dto.dimension.DimensionOrgDtoDashboard;
import pwc.taxtech.atms.dto.dimension.DimensionTypeEnum;
import pwc.taxtech.atms.dto.dimension.DimensionValueDisplayDto;
import pwc.taxtech.atms.dto.dimension.OrgDashboardParams;
import pwc.taxtech.atms.dto.navtree.DevTreeDto;
import pwc.taxtech.atms.dto.navtree.IvhTreeDto;
import pwc.taxtech.atms.dto.navtree.NavTreeDto;
import pwc.taxtech.atms.dto.organization.OrgCountDto;
import pwc.taxtech.atms.dto.organization.OrgCustomDto;
import pwc.taxtech.atms.dto.organization.OrgDisplayDto;
import pwc.taxtech.atms.dto.organization.OrgDto;
import pwc.taxtech.atms.dto.organization.OrgGeneralInfoDto;
import pwc.taxtech.atms.dto.user.NameDto;
import pwc.taxtech.atms.entity.*;
import pwc.taxtech.atms.entity.OrganizationExample.Criteria;
import pwc.taxtech.atms.exception.ApplicationException;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static java.util.Comparator.*;
import static java.util.stream.Collectors.toList;
import static pwc.taxtech.atms.common.CommonConstants.Comma;
import static pwc.taxtech.atms.common.CommonConstants.CommonFail;
import static pwc.taxtech.atms.common.CommonUtils.copyProperties;
import static pwc.taxtech.atms.common.OperateLogType.OperationLogOrganization;
import static pwc.taxtech.atms.common.OperationModule.Organization;
import static pwc.taxtech.atms.common.message.EnterpriseAccountSetOrgMessage.EffectiveDateAreaProblem;
import static pwc.taxtech.atms.common.message.EnterpriseAccountSetOrgMessage.EnterpriseAccountSetOrgDateTimeOverlap;
import static pwc.taxtech.atms.common.message.LogMessage.AddOrganization;

/**
 * @author rzhou038
 */
@Service
public class OrganizationServiceImpl {

    @Autowired
    private OrganizationMapper organizationMapper;

    @Autowired
    private IndustryMapper industryMapper;

    @Autowired
    private StatisticAttributeServiceImpl statisticAttributeService;

    @Autowired
    private DimensionServiceImpl dimensionService;

    @Autowired
    private CommonServiceImpl commonService;

    @Autowired
    private RoleServiceImpl roleService;

    @Autowired
    private BusinessUnitMapper businessUnitMapper;

    @Autowired
    private DimensionMapper dimensionMapper;

    @Autowired
    private UserDimensionValueMapper userDimensionValueMapper;

    @Autowired
    private UserDimensionValueOrgMapper userDimensionValueOrgMapper;

    @Autowired
    private UserOrganizationMapper userOrganizationMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private UserDimensionValueRoleMapper userDimensionValueRoleMapper;

    @Autowired
    private RegionMapper regionMapper;

    @Autowired
    private AreaMapper areaMapper;

    @Autowired
    private OrganizationStructureMapper organizationStructureMapper;

    @Autowired
    private UserOrganizationRoleMapper userOrganizationRoleMapper;

    @Autowired
    private DimensionValueMapper dimensionValueMapper;

    @Autowired
    private OperationLogServiceImpl operationLogService;

    @Autowired
    private EnterpriseAccountSetOrgMapper enterpriseAccountSetOrgMapper;

    @Autowired
    private ServiceTypeMapper serviceTypeMapper;

    @Autowired
    private OrganizationServiceTemplateGroupMapper organizationServiceTemplateGroupMapper;
    @Autowired
    private AreaRegionMapper areaRegionMapper;

    @Autowired
    private TaxPayerReportRuleMapper taxPayerReportRuleMapper;

    @Autowired
    private TemplateGroupMapper templateGroupMapper;

    @Autowired
    private DimensionValueOrgMapper dimensionValueOrgMapper;

    @Autowired
    private EnterpriseAccountSetMapper enterpriseAccountSetMapper;
    @Autowired
    private DistributedIdService distributedIdService;

    private static final Logger logger = LoggerFactory.getLogger(ProjectServiceImpl.class);

    public boolean isOrganizationStructureExists(String organizationStructureId) {
        OrganizationExample example = new OrganizationExample();
        example.createCriteria().andStructureIdEqualTo(organizationStructureId);
        return organizationMapper.countByExample(example) > 0;
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * pwc.taxtech.atms.service.OrganizationService#getLinkedOrganization(java.util.
     * List)
     */
    public List<Organization> getLinkedOrganization(List<Area> areaList) {

        List<String> areaIdList = areaList.stream().map(area -> area.getId()).collect(Collectors.toList());

        OrganizationExample organizationExample = new OrganizationExample();
        pwc.taxtech.atms.entity.OrganizationExample.Criteria criteria = organizationExample.createCriteria();
        criteria.andIsActiveEqualTo(CommonConstants.ACTIVE_STATUS);
        criteria.andAreaIdIn(areaIdList);
        List<Organization> organizationList = organizationMapper.selectByExample(organizationExample);
        return organizationList;
    }

    public List<NavTreeDto> getOrgListToJson(Integer useType) {
        List<OrganizationDto> orgList = getOrgList(useType);
        return orgList.stream().map(this::rotateOrganizationDtoToNavTreeDto).collect(Collectors.toList());
    }

    private NavTreeDto rotateOrganizationDtoToNavTreeDto(OrganizationDto organizationDto) {
        NavTreeDto navTreeDto = new NavTreeDto();
        navTreeDto.setLabel(organizationDto.getName());
        navTreeDto.setData(organizationDto);
        navTreeDto.setChildren(organizationDto.getSubOrgs().stream().map(this::rotateOrganizationDtoToNavTreeDto)
                .collect(Collectors.toList()));
        return navTreeDto;
    }

    public List<OrganizationDto> getOrgList(Integer useType) {
        List<OrganizationDto> orgDtoList = new ArrayList<>();
        List<Organization> orgList = findAllOrganizations();
        if (!orgList.isEmpty()) {
            // find rootOrg
            List<Organization> rootOrgs = null;
            if (useType == 1) {
                rootOrgs = orgList.stream().filter(x -> x.getParentId() == null).collect(Collectors.toList());
            } else {
                rootOrgs = orgList.stream()
                        .filter(x -> x.getParentId() == null && CommonConstants.ACTIVE_STATUS.equals(x.getIsActive()))
                        .collect(Collectors.toList());
            }

            List<ServiceType> serviceList = new ArrayList<>();
            for (Organization rootOrg : rootOrgs) {
                OrganizationDto rootDto = rotateOrganizationToOrganizationDto(rootOrg);
                OrganizationDto subOrgs = genarateSubOrgs(rootDto, orgList, serviceList, useType);
                orgDtoList.add(subOrgs);
            }
        }
        orgDtoList.sort((OrganizationDto o1, OrganizationDto o2) -> o1.getName().compareTo(o2.getName()));
        return orgDtoList;
    }

    private OrganizationDto genarateSubOrgs(OrganizationDto parentOrg, List<Organization> orgs,
                                            List<ServiceType> serviceList, Integer useType) {
        if (parentOrg.getParentId() != null) {
            Organization organization = orgs.stream().filter(x -> x.getId().equals(parentOrg.getParentId()))
                    .collect(Collectors.toList()).get(0);
            parentOrg.setParentName(organization == null ? null : organization.getName());
        }
        List<Organization> subOrgs = null;
        if (useType == 1) {
            subOrgs = orgs.stream().filter(x -> parentOrg.getId().equals(x.getParentId())).collect(Collectors.toList());
        } else {
            subOrgs = orgs.stream().filter(x -> parentOrg.getId().equals(x.getParentId())
                    && CommonConstants.ACTIVE_STATUS.equals(x.getIsActive())).collect(Collectors.toList());
        }
        parentOrg.setSubOrgs(new ArrayList<>());

        // create and add subtrees to the current node
        for (Organization subOrg : subOrgs) {
            OrganizationDto subDto = rotateOrganizationToOrganizationDto(subOrg);
            subDto.setLevel(parentOrg.getLevel() == null ? 1 : parentOrg.getLevel() + 1);
            parentOrg.getSubOrgs().add(genarateSubOrgs(subDto, orgs, serviceList, useType));
        }
        return parentOrg;
    }

    private OrganizationDto rotateOrganizationToOrganizationDto(Organization organization) {
        OrganizationDto organizationDto = new OrganizationDto();
        CommonUtils.copyProperties(organization, organizationDto);
        return organizationDto;
    }

    private IndustryDto rotateIndustryToIndustryDto(Industry industry) {
        IndustryDto industryDto = new IndustryDto();
        return CommonUtils.copyProperties(industry, industryDto);
    }

    /*
     * (non-Javadoc)
     *
     * @see pwc.taxtech.atms.service.OrganizationService#GetOrganizationFilterList()
     */
    public List<OrganizationDto> getOrganizationFilterList() {

        OrganizationExample example = new OrganizationExample();
        example.setOrderByClause("Name ASC");
        List<Organization> organizationList = organizationMapper.selectByExampleWithAssociation(example);

        if (organizationList == null || organizationList.isEmpty()) {
            return new ArrayList<>();
        }
        List<OrganizationDto> organizationDtoList = new ArrayList<>();
        for (Organization organization : organizationList) {
            OrganizationDto organizationDto = new OrganizationDto();
            CommonUtils.copyProperties(organization, organizationDto);
            organizationDto.setAreaName(organization.getArea() != null ? organization.getArea().getName() : "");
            organizationDto.setBusinessUnitName(
                    organization.getBusinessUnitId() != null && organization.getBusinessUnit() != null ? organization.getBusinessUnit().getName() : "");
            organizationDtoList.add(organizationDto);
        }
        return organizationDtoList;
    }

    public List<Organization> findAllOrganizations() {
        OrganizationExample organizationExample = new OrganizationExample();
        return organizationMapper.selectByExample(organizationExample);
    }

    public List<IndustryDto> getProjectIndustryList() {
        logger.debug("获取Project Industrys Start");
        IndustryExample example = new IndustryExample();
        example.setOrderByClause("id asc");
        pwc.taxtech.atms.entity.IndustryExample.Criteria criteria = example.createCriteria();
        criteria.andIsActiveEqualTo(true);

        List<Industry> industryList = industryMapper.selectByExample(example);
        List<String> distinctName = industryList.stream().map(ind -> ind.getName()).distinct()
                .collect(Collectors.toList());
        List<IndustryDto> retList = new ArrayList<IndustryDto>();
        // 遍历disName,将返回的industry转换为IndustryDto,加入到retList
        distinctName.stream().forEach(
                disName -> retList.add(rotateIndustryToIndustryDto(findFirstListByName(disName, industryList))));
        return retList;
    }

    // 返回industry中名字为industryName的第一个Industry
    private Industry findFirstListByName(String industryName, List<Industry> industryList) {
        return (industryName == null || industryList.isEmpty()) ? null
                : industryList.stream().filter(industry -> (Strings.equals(industry.getName(), industryName)))
                .findFirst().orElse(null);
    }

    public List<OrgBasicDto> getOrgListLevel() {
        return organizationMapper.selectIndBusiunitAreaOrgstrctReg(false);
    }

    /**
     * Organization表中根据行业,事业部,区域关联起来
     */
    private List<OrganizationDto> getOrganizationJoinResult(Boolean orgIsActive) {
        return organizationMapper.selectIndBusiunitAreaOrgstrct(orgIsActive);
    }

    public List<OrganizationDto> getOrganizationJoinResult() {
        return getOrganizationJoinResult(true);
    }

    public Boolean taxPayerNumberUniqueValidate(OrganizationValidateDto validateDto) {
        String innerId = Strings.sBlank(validateDto.getId()).trim();
        String innerNumber = Strings.sBlank(validateDto.getValue()).trim();
        if (Strings.isBlank(innerNumber))
            return true;
        OrganizationExample example = new OrganizationExample();
        pwc.taxtech.atms.entity.OrganizationExample.Criteria criteria = example.createCriteria();
        criteria.andTaxPayerNumberEqualTo(innerNumber);
        List<Organization> result = organizationMapper.selectByExample(example);
        return !result.stream().anyMatch(res -> (Strings.isBlank(innerId)) || !innerId.equals(res.getId()));
    }

    /**
     * 自定义维度显示属性,在机构管理顶部点击某个维度的时候,显示下面维度的属性,Orgchart结构树(Jack)
     */
    public List<DimensionOrgDtoDashboard> getOrgDashboard(String parentDimensionId, String parentOrgId,
                                                          OrgDashboardParams param) {
        List<String> expandedOrgList = (param == null ? null : param.getExpandedOrgList());
        String filterFlag = (param == null ? null : param.getFilterFlag());

        // C#中在此处新建了变量List<DimensionOrgDtoDashboard> displayList,但无任何引用,故删除。
        if (expandedOrgList == null) {
            expandedOrgList = new ArrayList<>();
        }
        List<StatisticAttributeDisplayDto> rawAttrList = new ArrayList<>();
        List<DimensionValueDisplayDto> dimensionValueList = new ArrayList<>();
        List<StatisticAttributeDisplayDto> attrDtoList = statisticAttributeService
                .getStatisticAttributeListByDimensionId(parentDimensionId, rawAttrList);
        if (!DimensionConstant.OrgSubChildrenId.equals(parentDimensionId)) {
            List<OrganizationDto> query;
            query = getOrgDimensionMappingForDimension(parentDimensionId).stream()
                    .filter(org -> Objects.equals(org.getDimensionId(), parentDimensionId))
                    .collect(Collectors.toList());
            logger.debug("Size of query in getOrgDashboard is {}", query.size());
            query.stream().forEach(q -> addToDimensionValueList(q, dimensionValueList));
            logger.debug("Size of dimensionValueList in getOrgDashboard is {}", dimensionValueList.size());
            return getStatisticCount(dimensionValueList, parentDimensionId, query, attrDtoList);
        } else {
            // 机构基础数据包括区域,层级,自定义等等
            List<OrganizationDto> orgMappingResult = getOrgDimensionMappingForDimension(parentDimensionId).stream()
                    .filter(orgDto -> parentDimensionId != null && parentDimensionId.equals(orgDto.getDimensionId()))
                    .collect(Collectors.toList());

            List<StatisticAttributeDisplayDto> orgAttrList = rawAttrList.stream()
                    .sorted(Comparator.comparing(statisticAttributeDisplayDto -> Optional
                            .ofNullable(statisticAttributeDisplayDto.getOrderIndex()).orElse(0)))
                    .limit(2).collect(Collectors.toList());

            // 也就是UI显示的节点List
            List<OrganizationDto> orgDtoList = new ArrayList<>();
            String currentOrgId = "";
            if (Strings.isNotBlank(parentOrgId) && parentOrgId.contains("@@Current@@")) {
                currentOrgId = parentOrgId.replace("@@Current@@", "").trim();
            }
            if (Strings.isBlank(parentOrgId) || Strings.equals(parentOrgId, "0")) {
                // 如果父机构Id为空,那么获取第一层全部的机构
                orgDtoList = orgMappingResult.stream().filter(orgMapRes -> Strings.isBlank(orgMapRes.getParentId()))
                        .collect(Collectors.toList());
            } else if ("1".equals(parentOrgId)) {
                orgDtoList = orgMappingResult.stream().filter(orgMapRes -> Strings.isBlank(orgMapRes.getParentId())
                        && Strings.isNotBlank(orgMapRes.getTaxPayerNumber())).collect(Collectors.toList());
            } else if ("2".equals(parentOrgId)) {
                orgDtoList = orgMappingResult.stream().filter(orgMapRes -> Strings.isBlank(orgMapRes.getParentId())
                        && Strings.isBlank(orgMapRes.getTaxPayerNumber())).collect(Collectors.toList());
            } else {
                // 只获取指定节点的子节点信息

                // 创建临时变量
                String currentOrgIdTemp = currentOrgId;
                if ("0".equals(filterFlag) || Strings.isBlank(filterFlag)) {
                    if (Strings.isNotBlank(currentOrgIdTemp)) {
                        orgDtoList = orgMappingResult.stream()
                                .filter(x -> currentOrgIdTemp != null && currentOrgIdTemp.equals(x.getId()))
                                .collect(Collectors.toList());
                    } else {
                        orgDtoList = orgMappingResult.stream()
                                .filter(x -> parentOrgId != null && parentOrgId.equals(x.getParentId()))
                                .collect(Collectors.toList());
                    }
                } else if ("1".equals(filterFlag)) {
                    if (Strings.isNotBlank(currentOrgIdTemp)) {
                        orgDtoList = orgMappingResult.stream().filter(x -> currentOrgIdTemp != null
                                && currentOrgIdTemp.equals(x.getId()) && Strings.isNotBlank(x.getTaxPayerNumber()))
                                .collect(Collectors.toList());
                    } else {
                        orgDtoList = orgMappingResult.stream().filter(x -> parentOrgId != null
                                && parentOrgId.equals(x.getParentId()) && Strings.isNotBlank(x.getTaxPayerNumber()))
                                .collect(Collectors.toList());
                    }
                } else if ("2".equals(filterFlag)) {
                    if (Strings.isNotBlank(currentOrgIdTemp)) {
                        orgDtoList = orgMappingResult.stream().filter(x -> currentOrgIdTemp != null
                                && currentOrgIdTemp.equals(x.getId()) && Strings.isNotBlank(x.getTaxPayerNumber()))
                                .collect(Collectors.toList());
                    } else {
                        orgDtoList = orgMappingResult.stream().filter(x -> parentOrgId != null
                                && parentOrgId.equals(x.getParentId()) && Strings.isBlank(x.getTaxPayerNumber()))
                                .collect(Collectors.toList());
                    }
                }
            }
            if ("1".equals(parentOrgId) || "2".equals(parentOrgId)) {
                filterFlag = parentOrgId;
            }

            return getOrgChartDisplayData(orgDtoList, orgAttrList, parentDimensionId, orgMappingResult, attrDtoList,
                    expandedOrgList, filterFlag);
        }
    }

    private List<DimensionOrgDtoDashboard> getOrgChartDisplayData(List<OrganizationDto> orgList,
                                                                  List<StatisticAttributeDisplayDto> orgAttrList, String parentDimensionId,
                                                                  List<OrganizationDto> orgMappingResult, List<StatisticAttributeDisplayDto> attrDtoList,
                                                                  List<String> expandedOrgList, String filterFlag) {
        List<OrganizationDto> allOrgList = getAllOrgList();

        // 自定义维度与之关联的机构列表
        List<DimensionValueDisplayDto> dimensionValueList = getDimensionValueDisplayDtoList(orgList, orgAttrList,
                allOrgList);

        // 各种统计
        List<DimensionOrgDtoDashboard> statisticList = getStatisticCount(dimensionValueList, parentDimensionId,
                orgMappingResult, attrDtoList, allOrgList);

        // 获取orgQuery下的子机构
        // 判断是否存在子节点,如果存在的话,需要返回标记
        for (OrganizationDto item : orgList) {
            List<OrganizationDto> childrenOrgList = new ArrayList<>();
            if (!"1".equals(filterFlag) && !"2".equals(filterFlag)) {
                childrenOrgList = orgMappingResult.stream().filter(x -> Objects.equals(x.getParentId(), item.getId()))
                        .collect(Collectors.toList());
            } else if ("1".equals(filterFlag)) {
                childrenOrgList = orgMappingResult.stream().filter(
                        x -> Objects.equals(x.getParentId(), item.getId()) && Strings.isNotBlank(x.getTaxPayerNumber()))
                        .collect(Collectors.toList());
            } else if ("2".equals(filterFlag)) {
                childrenOrgList = orgMappingResult.stream().filter(
                        x -> Objects.equals(x.getParentId(), item.getId()) && Strings.isBlank(x.getTaxPayerNumber()))
                        .collect(Collectors.toList());
            }

            // 找出与之关联的统计卡片对象,并赋值给children属性
            DimensionOrgDtoDashboard childOrg = statisticList.stream()
                    .filter(x -> item.getId() != null && item.getId().equals(x.getDimensionValueId())).findFirst()
                    .orElse(null);
            Assert.notNull(childOrg, "Null childOrg");
            childOrg.setHasChildren(!childrenOrgList.isEmpty());

            if (expandedOrgList.contains(item.getId())) {
                // new added Jacob on 07-03
                List<DimensionValueDisplayDto> childrenDimensionValueList = getDimensionValueDisplayDtoList(
                        childrenOrgList, orgAttrList, allOrgList);
                List<DimensionOrgDtoDashboard> childrenStatisticList = getStatisticCount(childrenDimensionValueList,
                        parentDimensionId, orgMappingResult, attrDtoList, allOrgList);
                childOrg.setChildren(childrenStatisticList);

                getSubStatisticRecursion(childrenOrgList, orgAttrList, allOrgList, parentDimensionId, orgMappingResult,
                        attrDtoList, childrenStatisticList, expandedOrgList, filterFlag);
            }
        }
        return statisticList;
    }

    private void getSubStatisticRecursion(List<OrganizationDto> subOrgList,
                                          List<StatisticAttributeDisplayDto> orgAttrList, List<OrganizationDto> allOrgList, String parentDimensionId,
                                          List<OrganizationDto> orgMappingResult, List<StatisticAttributeDisplayDto> attrDtoList,
                                          List<DimensionOrgDtoDashboard> parentStatisticList, List<String> expandedOrgList, String filterFlag) {
        if (subOrgList.isEmpty())
            return;

        // 获取orgQuery下的子机构
        for (OrganizationDto item : subOrgList) {
            List<OrganizationDto> childrenOrgList = new ArrayList<>();
            if (!"1".equals(filterFlag) && !"2".equals(filterFlag)) {
                childrenOrgList = orgMappingResult.stream().filter(x -> Objects.equals(x.getParentId(), item.getId()))
                        .collect(Collectors.toList());
            } else if ("1".equals(filterFlag)) {
                childrenOrgList = orgMappingResult.stream().filter(
                        x -> Objects.equals(x.getParentId(), item.getId()) && Strings.isNotBlank(x.getTaxPayerNumber()))
                        .collect(Collectors.toList());
            } else if ("2".equals(filterFlag)) {
                childrenOrgList = orgMappingResult.stream().filter(
                        x -> Objects.equals(x.getParentId(), item.getId()) && Strings.isBlank(x.getTaxPayerNumber()))
                        .collect(Collectors.toList());
            }
            if (childrenOrgList.isEmpty()) {
                return;
            }
            // 找出与之关联的统计卡片对象,并赋值给children属性
            DimensionOrgDtoDashboard childOrg = parentStatisticList.stream()
                    .filter(x -> item.getId() != null && item.getId().equals(x.getDimensionValueId())).findFirst()
                    .orElse(null);
            Assert.notNull(childOrg, "Null childOrg");
            childOrg.setHasChildren(!childrenOrgList.isEmpty());

            if (expandedOrgList.contains(item.getId())) {
                List<DimensionValueDisplayDto> childrenDimensionValueList = getDimensionValueDisplayDtoList(
                        childrenOrgList, orgAttrList, allOrgList);
                List<DimensionOrgDtoDashboard> childrenStatisticList = getStatisticCount(childrenDimensionValueList,
                        parentDimensionId, orgMappingResult, attrDtoList, allOrgList);
                childOrg.setChildren(childrenStatisticList);

                getSubStatisticRecursion(childrenOrgList, orgAttrList, allOrgList, parentDimensionId, orgMappingResult,
                        attrDtoList, childrenStatisticList, expandedOrgList, filterFlag);
            }
        }
    }

    /**
     * 根据机构的列表 转化为展示DTO
     */
    private List<DimensionValueDisplayDto> getDimensionValueDisplayDtoList(List<OrganizationDto> orgQuery,
                                                                           List<StatisticAttributeDisplayDto> orgAttrList, List<OrganizationDto> orgAllData) {
        List<OrganizationDto> allCustomDimensionOrg = getAllCustomDimensionOrgList();
        return orgQuery.stream()
                .map(orgQ -> rotateOrgDtoToDimValDisplayDto(orgQ, orgAttrList, allCustomDimensionOrg, orgAllData))
                .filter(s -> !Strings.isBlank(s.getDimensionValueId())).distinct().collect(Collectors.toList());
    }

    private DimensionValueDisplayDto rotateOrgDtoToDimValDisplayDto(OrganizationDto orgDto,
                                                                    List<StatisticAttributeDisplayDto> orgAttrList, List<OrganizationDto> allCustomDimensionOrg,
                                                                    List<OrganizationDto> orgAllData) {
        DimensionValueDisplayDto dVDDto = new DimensionValueDisplayDto();
        dVDDto.setDimensionValueId(orgDto.getId());
        dVDDto.setDimensionValueName(orgDto.getName());
        dVDDto.setFirstAttrValue(getAttrValue(!orgAttrList.isEmpty() ? orgAttrList.get(0) : null, orgDto,
                allCustomDimensionOrg, orgAllData));
        dVDDto.setSecondAttrValue(getAttrValue(orgAttrList.size() > 1 ? orgAttrList.get(1) : null, orgDto,
                allCustomDimensionOrg, orgAllData));
        return dVDDto;
    }

    private String getAttrValue(StatisticAttributeDisplayDto statAttrDto, OrganizationDto org,
                                List<OrganizationDto> allCustomDimensionOrg, List<OrganizationDto> allOrgDto) {
        if (statAttrDto == null) {
            return null;
        }
        OrganizationDto orgData = allOrgDto.stream().filter(x -> Objects.equals(org.getId(), x.getId())).findFirst()
                .orElse(null);
        Assert.notNull(orgData, "Null OrgData");
        List<OrganizationDto> dimensionValueOrgList = allCustomDimensionOrg.stream()
                .filter(x -> Objects.equals(org.getId(), x.getId())).collect(Collectors.toList());
        String attrValueName = "";

        AttributeTypeEnum enumValue = AttributeTypeEnum.valueOf(statAttrDto.getAttributeType());
        Assert.notNull(enumValue, "Null AttributeTypeEnum");
        switch (enumValue) {
            case Area:
                attrValueName = getAreaName(org, orgData.getAreaId());
                break;
            case BusinessUnit:
                attrValueName = getBusinessUnitName(org, orgData.getBusinessUnitId());
                break;
            case Industry:
                attrValueName = org.getIndustryName();
                break;
            case OrganizationStructure:
                attrValueName = getStructureName(org, orgData.getStructureId());
                break;
            case OrgCode:
                attrValueName = org.getCode();
                break;
            case TaxPayerNumber:
                attrValueName = org.getTaxPayerNumber();
                break;
            case RegionId:
                // 原语句中orgData.getStructureId()未被使用,检查是否有问题
                // attrValueName = getRegion(org, orgData.getStructureId());
                attrValueName = getRegion(org);
                break;
            case SelfDimension:
                List<OrganizationDto> list = dimensionValueOrgList.stream()
                        .filter(x -> Objects.equals(x.getAttributeId(), statAttrDto.getAttributeId()))
                        .collect(Collectors.toList());
                if (!list.isEmpty()) {
                    attrValueName = list.get(0).getDimensionValueName();
                } else {
                    attrValueName = null;
                }
                break;
            default:
                logger.warn("enumValue not matched in getAttrValue");
        }
        return attrValueName;
    }

    private String getRegion(OrganizationDto org) {
        // C#中原传参businessUnitId未被使用,检查是否有问题
        Region region = null;
        if (org.getRegionId() != null) {
            RegionExample example = new RegionExample();
            pwc.taxtech.atms.entity.RegionExample.Criteria criteria = example.createCriteria();
            criteria.andIdEqualTo(org.getRegionId());
            region = regionMapper.selectByExample(example).stream().findFirst().orElse(null);
        }

        if (region != null) {
            return region.getName();
        }
        return "";
    }

    private String getAreaName(OrganizationDto org, String areaId) {
        if (Strings.isBlank(org.getAreaName())) {
            if (areaId != null) {
                AreaExample example = new AreaExample();
                pwc.taxtech.atms.entity.AreaExample.Criteria criteria = example.createCriteria();
                criteria.andIdEqualTo(areaId);
                org.setAreaName(
                        areaMapper.selectByExample(example).stream().map(am -> am.getName()).findFirst().orElse(null));
            } else {
                org.setAreaName(null);
            }

        }
        return org.getAreaName();
    }

    private String getBusinessUnitName(OrganizationDto org, String businessUnitId) {
        if (Strings.isBlank(org.getBusinessUnitName())) {
            if (businessUnitId != null) {
                BusinessUnitExample example = new BusinessUnitExample();
                pwc.taxtech.atms.entity.BusinessUnitExample.Criteria criteria = example.createCriteria();
                criteria.andIdEqualTo(businessUnitId);
                org.setBusinessUnitName(businessUnitMapper.selectByExample(example).stream().map(bu -> bu.getName())
                        .findFirst().orElse(null));
            } else {
                org.setBusinessUnitName(null);
            }
        }
        return org.getBusinessUnitName();
    }

    private String getStructureName(OrganizationDto org, String structureId) {
        if (Strings.isBlank(org.getStructureName())) {
            if (structureId != null) {
                OrganizationStructureExample example = new OrganizationStructureExample();
                pwc.taxtech.atms.entity.OrganizationStructureExample.Criteria criteria = example.createCriteria();
                criteria.andIdEqualTo(structureId);
                org.setStructureName(organizationStructureMapper.selectByExample(example).stream()
                        .map(os -> os.getName()).findFirst().orElse(null));
            } else {
                org.setStructureName(null);
            }
        }
        return org.getStructureName();
    }

    private List<OrganizationDto> getAllCustomDimensionOrgList() {
        return organizationMapper.getAllCustomDimensionOrgList();
    }

    private List<OrganizationDto> getAllOrgList() {
        return organizationMapper.selectByExample(null).stream().map(this::rotateOrgToOrgDto)
                .collect(Collectors.toList());
    }

    private OrganizationDto rotateOrgToOrgDto(Organization org) {
        OrganizationDto orgDto = new OrganizationDto();
        orgDto.setId(org.getId());
        orgDto.setName(org.getName());
        orgDto.setBusinessUnitId(org.getBusinessUnitId());
        orgDto.setStructureId(org.getStructureId());
        orgDto.setRegionId(org.getRegionId());
        orgDto.setAreaId(org.getAreaId());
        orgDto.setParentId(org.getParentId());
        return orgDto;
    }

    private List<DimensionOrgDtoDashboard> getStatisticCount(List<DimensionValueDisplayDto> dimensionValueList,
                                                             String parentDimensionId, List<OrganizationDto> query, List<StatisticAttributeDisplayDto> attrDtoList) {
        return getStatisticCount(dimensionValueList, parentDimensionId, query, attrDtoList, null);
    }

    private List<DimensionOrgDtoDashboard> getStatisticCount(List<DimensionValueDisplayDto> dimensionValueList,
                                                             final String parentDimensionId, List<OrganizationDto> query, List<StatisticAttributeDisplayDto> attrDtoList,
                                                             List<OrganizationDto> allOrgList) {
        List<DimensionOrgDtoDashboard> displayList = new ArrayList<>();
        // 获取自定义维度的所有机构
        List<OrganizationDto> allCustomDimensionOrg = getCustomDimensionOrgList();

        // 维度值的列表,多少维度,如产品维度,值为产品1,产品2,产品3 等
        List<UserDimensionValue> userDimensionValueList = new ArrayList<>();
        List<UserDimensionValueOrg> userDimensionValueOrgList = new ArrayList<>();
        List<UserOrganization> userOrganizationList = new ArrayList<>();
        List<UserOrgRoleDto> originalRoleList = new ArrayList<>();
        List<UserOrgRoleDto> userDimensionValueRoleList = new ArrayList<>();
        List<UserOrgRoleDto> userOrganizationRoleList = new ArrayList<>();
        List<OrganizationDto> userAllDimensionList = new ArrayList<>();
        // 如果有用户数的属性
        if (attrDtoList.stream().anyMatch(attDto -> AttributeTypeEnum.User.value().equals(attDto.getAttributeType()))) {
            populateUserRoleBasic(userDimensionValueList, userDimensionValueOrgList, userOrganizationList,
                    originalRoleList, userDimensionValueRoleList, userOrganizationRoleList);

            if (DimensionConstant.OrgSubChildrenId.equals(parentDimensionId)) {
                userAllDimensionList = getDimensionValueOrgDtoList().stream().map(this::rotateToOrganizationDto)
                        .collect(Collectors.toList());
            }
        }
        List<OrganizationDto> userAllDimensionListTemp = userAllDimensionList;
        if (logger.isDebugEnabled())
            logger.debug("function: getStatisticCount before filter, Size of dimensionValueList:{} ",
                    dimensionValueList.size());
        for (DimensionValueDisplayDto val : dimensionValueList) {
            DimensionOrgDtoDashboard dtoDashboard = new DimensionOrgDtoDashboard();
            List<OrganizationDto> valueList;

            // 维度的属性值,如产品1,产品2,产品3
            dtoDashboard.setDimensionValueId(val.getDimensionValueId());
            dtoDashboard.setDimensionValue(val.getDimensionValueName());
            dtoDashboard.setFirstAttrName(val.getFirstAttrValue());
            dtoDashboard.setSecondAttrName(val.getSecondAttrValue());
            dtoDashboard.setHasChildren(false);

            // 每个维度值下面的属性统计
            if (!DimensionConstant.OrgSubChildrenId.equals(parentDimensionId)) {
                valueList = query.stream()
                        .filter(q -> val.getDimensionValueId() != null
                                && val.getDimensionValueId().equals(q.getDimensionValueId()))
                        .collect(Collectors.toList());
            } else {
                String orgId = val.getDimensionValueId();
                // 获取该机构下所有的子机构,速度很差
                List<String> orgList = getChildrenOrgIdToList(orgId, allOrgList).stream()
                        .filter(str -> orgId != null && !orgId.equals(str)).collect(Collectors.toList());
                // 子机构
                valueList = query.stream().filter(q -> orgList.contains(q.getId())).collect(Collectors.toList());
            }

            List<UserOrgDto> dimensionUser = new ArrayList<>();
            // 如果有用户数的属性
            if (attrDtoList.stream()
                    .anyMatch(attrDto -> AttributeTypeEnum.User.value().equals(attrDto.getAttributeType()))) {
                if (DimensionConstant.OrgSubChildrenId.equals(parentDimensionId)) {
                    // 某个机构下的维度列表
                    List<OrganizationDto> orgDimensionTempList = userAllDimensionListTemp.stream()
                            .filter(userDimension -> val.getDimensionValueId() != null
                                    && val.getDimensionValueId().equals(userDimension.getId()))
                            .collect(Collectors.toList());
                    dimensionUser = roleService.getUserByDimensionValue(orgDimensionTempList, userDimensionValueList,
                            userDimensionValueOrgList, userOrganizationList, originalRoleList,
                            userDimensionValueRoleList, userOrganizationRoleList, parentDimensionId,
                            val.getDimensionValueId());
                } else {
                    dimensionUser = roleService.getUserByDimensionValue(valueList, userDimensionValueList,
                            userDimensionValueOrgList, userOrganizationList, originalRoleList,
                            userDimensionValueRoleList, userOrganizationRoleList, parentDimensionId,
                            val.getDimensionValueId());

                }
            }

            // 自定义显示维度属性
            // 传参String parentDimensionId 和 dimensionValueId 在C#中未被引用,故删除
            dtoDashboard.setOrgDtoList(
                    getOrgDtoStatisticsList(valueList, attrDtoList, allCustomDimensionOrg, dimensionUser));

            if (!displayList.stream().anyMatch(display -> dtoDashboard.getDimensionValueId() != null
                    && dtoDashboard.getDimensionValueId().equals(display.getDimensionValueId()))) {
                displayList.add(dtoDashboard);
            }

        }
        if (logger.isDebugEnabled())
            logger.debug("function: getStatisticCount after filter, Size of displayList: {}", displayList.size());
        return displayList;
    }

    // 传参String parentDimensionId 和 dimensionValueId 在C#中未被引用,故删除

    /**
     * 根据自定义属性,统计属性的值
     */
    private List<DimensionOrgDto> getOrgDtoStatisticsList(List<OrganizationDto> orgDtoList,
                                                          List<StatisticAttributeDisplayDto> attributeDtoList, List<OrganizationDto> allCustomDimensionOrg,
                                                          List<UserOrgDto> dimensionUserList) {
        List<DimensionOrgDto> dtoList = new ArrayList<>();
        // 统计的时候去掉没有机构的数据
        List<OrganizationDto> orgDtoListTemp = orgDtoList.stream().filter(s -> Strings.isNotBlank(s.getId()))
                .collect(Collectors.toList());
        // 自定义显示属性列表统计
        for (StatisticAttributeDisplayDto item : attributeDtoList) {
            DimensionOrgDto temp = new DimensionOrgDto();
            // 自定义维度Id
            temp.setAttributeId(item.getAttributeId());
            // 自定义维度名字
            temp.setAttributeName(item.getAttributeName());

            // 事业部
            if (AttributeTypeEnum.BusinessUnit.value().equals(item.getAttributeType())) {
                temp.setAttributeType(AttributeTypeEnum.BusinessUnit.value());
                // 统计当前维度,多少个事业部
                temp.setAttributeValueCount((int) (orgDtoListTemp.stream()
                        .map(org -> org.getBusinessUnitId() + org.getBusinessUnitName()).distinct().count()));
            } else if (AttributeTypeEnum.Area.value().equals(item.getAttributeType())) {
                // 覆盖区域
                temp.setAttributeType(AttributeTypeEnum.Area.value());
                // 统计当前维度,多少个覆盖区域
                temp.setAttributeValueCount((int) (orgDtoListTemp.stream().map(org -> {
                    return org.getAreaId();
                }).distinct().count()));
            } else if (AttributeTypeEnum.OrganizationStructure.value().equals(item.getAttributeType())) {
                // 机构层级
                temp.setAttributeType(AttributeTypeEnum.OrganizationStructure.value());
                // 统计当前维度,多少个子公司
                temp.setAttributeValueCount((int) (orgDtoListTemp.stream().map(org -> {
                    return org.getStructureId();
                }).distinct().count()));
            } else if (AttributeTypeEnum.OrgSubChildren.value().equals(item.getAttributeType())) {
                // 机构数
                temp.setAttributeType(AttributeTypeEnum.OrgSubChildren.value());
                // 统计当前维度,多少个机构
                temp.setAttributeValueCount(
                        (int) (orgDtoListTemp.stream().map(OrganizationDto::getId).distinct().count()));
            } else if (AttributeTypeEnum.User.value().equals(item.getAttributeType())) {
                // 用户数
                temp.setAttributeType(AttributeTypeEnum.User.value());
                // 统计当前维度,多少个用户数
                temp.setAttributeValueCount((int) (dimensionUserList.stream().map(du -> {
                    return (du.getUserId());
                }).distinct().count()));
            } else if (AttributeTypeEnum.Industry.value().equals(item.getAttributeType())) {
                // 所属行业
                temp.setAttributeType(AttributeTypeEnum.Industry.value());
                // 统计当前维度,多少个所属行业
                temp.setAttributeValueCount((int) (orgDtoListTemp.stream().map(org -> {
                    return org.getIndustryId();
                }).distinct().count()));
            } else {
                // 自定义的维度
                temp.setAttributeType(AttributeTypeEnum.SelfDimension.value());
                List<OrganizationDto> query = new ArrayList<>();
                allCustomDimensionOrg.stream().forEach(customDO -> {
                    orgDtoListTemp.stream().forEach(orgDto -> {
                        if (Objects.equals(customDO.getId(), orgDto.getId())) {
                            OrganizationDto tempQuery = new OrganizationDto();
                            tempQuery.setAttributeId(customDO.getAttributeId());
                            tempQuery.setAttributeName(customDO.getAttributeName());
                            tempQuery.setDimensionValueId(customDO.getDimensionValueId());
                            tempQuery.setDimensionValueName(customDO.getDimensionValueName());
                            query.add(tempQuery);
                        }
                    });
                });
                temp.setAttributeValueCount(
                        (int) query.stream().filter(q -> Objects.equals(item.getAttributeId(), q.getAttributeId()))
                                .map(q -> q.getDimensionValueId()).distinct().count());
            }
            dtoList.add(temp);
        }

        return dtoList;
    }

    private OrganizationDto rotateToOrganizationDto(DimensionValueOrgDto sDto) {
        OrganizationDto tDto = new OrganizationDto();
        tDto.setId(sDto.getOrganizationId());
        tDto.setName(sDto.getOrganizationName());
        tDto.setDimensionId(sDto.getDimensionId());
        tDto.setDimensionName(sDto.getDimensionName());
        tDto.setDimensionValueId(sDto.getDimensionValueId());
        tDto.setDimensionValueName(sDto.getDimensionValue());
        return tDto;
    }

    private List<String> getChildrenOrgIdToList(String parentOrgId, List<OrganizationDto> orgList) {
        List<String> childrenOrgIdList = new ArrayList<>();
        childrenOrgIdList.add(parentOrgId);
        List<OrganizationDto> query = orgList.stream()
                .filter(org -> parentOrgId != null && parentOrgId.equals(org.getParentId()))
                .collect(Collectors.toList());
        query.stream().forEach(item -> {
            childrenOrgIdList.add(item.getId());
            getChildrenOrgIdRecursion(item.getId(), childrenOrgIdList, orgList);
        });
        return childrenOrgIdList;
    }

    private void getChildrenOrgIdRecursion(String orgId, List<String> childrenOrgIdList,
                                           List<OrganizationDto> orgList) {
        List<OrganizationDto> query = orgList.stream().filter(org -> orgId != null && orgId.equals(org.getParentId()))
                .collect(Collectors.toList());
        if (query.isEmpty()) {
            return;
        }
        query.stream().forEach(item -> {
            childrenOrgIdList.add(item.getId());
            getChildrenOrgIdRecursion(item.getId(), childrenOrgIdList, orgList);
        });
    }

    public List<DimensionValueOrgDto> getDimensionValueOrgDtoList() {
        return organizationMapper.getDimensionValueOrgDtoList();
    }

    /**
     * 由于C#中OrganizationService.cs line 2356~2357以下代码被注释,故JAVA中未join
     * statDimension表做联合查询。 join sd in stat Dimension on d.id equals sd.DimensionId
     * from sdTp in sdTemp.DefaultIfEmpty()
     */
    private List<OrganizationDto> getCustomDimensionOrgList() {
        return organizationMapper.getCustomDimensionOrgList();
    }

    private void populateUserRoleBasic(List<UserDimensionValue> userDimensionValueList,
                                       List<UserDimensionValueOrg> userDimensionValueOrgList, List<UserOrganization> userOrganizationList,
                                       List<UserOrgRoleDto> originalRoleList, List<UserOrgRoleDto> userDimensionValueRoleList,
                                       List<UserOrgRoleDto> userOrganizationRoleList) {

        userDimensionValueList.addAll(userDimensionValueMapper.getUserDimensionValueList());
        userDimensionValueOrgList
                .addAll(userDimensionValueOrgMapper.selectByExample(new UserDimensionValueOrgExample()));
        userOrganizationList.addAll(userOrganizationMapper.getUserOrganizationList());
        /*
         * .NET中以下代码单纯从数据库查询出role表并join下列表进行联合查询,JAVA中将该逻辑直接在MapperXML中表达 var roleList =
         * (from r in this._dbContext.Set<Role>() select r);
         */
        originalRoleList.addAll(userRoleMapper.getOriginalRoleList());
        userDimensionValueRoleList.addAll(userDimensionValueRoleMapper.getUserDimensionValueRoleList());
        userOrganizationRoleList.addAll(userOrganizationRoleMapper.getUserOrganizationRoleList());
    }

    private void addToDimensionValueList(OrganizationDto orgDto, List<DimensionValueDisplayDto> dimensionValueList) {
        // 判定当Dimension List中没有任何一个DimensionValueId 与传入的Organization相等时执行
        Boolean hasValueWithDimensionValueId = !dimensionValueList.stream()
                .anyMatch(dv -> Objects.equals(orgDto.getDimensionValueId(), dv.getDimensionValueId()));

        if (StringUtils.isNotEmpty(orgDto.getDimensionId()) && hasValueWithDimensionValueId) {
            DimensionValueDisplayDto dValue = new DimensionValueDisplayDto();
            dValue.setDimensionValueId(orgDto.getDimensionValueId());
            dValue.setDimensionValueName(orgDto.getDimensionValueName());
            dimensionValueList.add(dValue);
        }
    }

    private List<OrganizationDto> getOrgDimensionMappingForDimension(String dimensionId) {
        List<OrganizationDto> basicQuery = new ArrayList<>();
        DimensinTypeOrgDto dimensionDto = dimensionService.getDimensionById(dimensionId);
        Integer dimensionType = dimensionDto.getDimensionType();
        List<OrganizationDto> query = basicQuery;
        if (DimensionTypeEnum.BusinessUnit.value().equals(dimensionType)) {
            basicQuery = getBusinessUnitListJoinResult();
            query = basicQuery.stream().map(bQuery -> transBUAndOSCResult(bQuery, dimensionId, dimensionDto)).distinct()
                    .collect(Collectors.toList());
        } else if (DimensionTypeEnum.OrgSubChildren.value().equals(dimensionType)) {
            basicQuery = getOrganizationJoinResult();
            query = basicQuery.stream().map(bQuery -> transBUAndOSCResult(bQuery, dimensionId, dimensionDto)).distinct()
                    .collect(Collectors.toList());
        } else if (DimensionTypeEnum.SelfDimension.value().equals(dimensionType)) {
            // query = dimensionMapper.getBusinessUnitListJoinDimensionResult(dimensionId,
            // true).stream()
            // .map(this::filterOrgDtoNullValueForSelfDimension).collect(Collectors.toList());
            query = dimensionMapper.getBusinessUnitListJoinDimensionResult(dimensionId, true);
        } else {
            /**
             * C#中源代码将查询结果赋值给basicQuery未做任何后续传出处理,无意义 basicQuery =
             * getOrganizationJoinResult();
             */
        }
        return query;
    }

    private List<OrganizationDto> getBusinessUnitListJoinResult() {
        return businessUnitMapper.getBusinessUnitListJoinResult();
    }

    // private OrganizationDto filterOrgDtoNullValue(OrganizationDto orgDto) {
    // orgDto.setStructureName(orgDto.getStructureName() == null ? "" :
    // orgDto.getStructureName());
    // orgDto.setIndustryId(orgDto.getIndustryId() == null ? "" :
    // orgDto.getIndustryId());
    // orgDto.setRegionId(orgDto.getRegionId() == null ? "" : orgDto.getRegionId());
    // orgDto.setRegionName(orgDto.getRegionName() == null ? "" :
    // orgDto.getRegionName());
    // orgDto.setStructureId(orgDto.getStructureId() == null ? "" :
    // orgDto.getStructureId());
    // orgDto.setAreaId(orgDto.getAreaId() == null ? "" : orgDto.getAreaId());
    // orgDto.setAreaName(orgDto.getAreaName() == null ? "" : orgDto.getAreaName());
    // orgDto.setClientCode(orgDto.getClientCode() == null ? "" :
    // orgDto.getClientCode());
    // orgDto.setCode(orgDto.getCode() == null ? "" : orgDto.getCode());
    // orgDto.setParentId(orgDto.getParentId() == null ? "" : orgDto.getParentId());
    // orgDto.setpLevel(orgDto.getpLevel() == null ? 0 : orgDto.getpLevel());
    // return orgDto;
    // }

    private OrganizationDto transBUAndOSCResult(OrganizationDto rawDto, String dimensionId,
                                                DimensinTypeOrgDto dimensionDto) {
        OrganizationDto newDto = new OrganizationDto();
        newDto.setBusinessUnitId(rawDto.getBusinessUnitId());
        newDto.setBusinessUnitName(rawDto.getBusinessUnitName());
        newDto.setId(rawDto.getId());
        newDto.setName(rawDto.getName());
        newDto.setDimensionId(dimensionId);
        newDto.setDimensionName(dimensionDto.getName());
        newDto.setDimensionValueId(rawDto.getBusinessUnitId());
        newDto.setDimensionValueName(rawDto.getBusinessUnitName());

        newDto.setAttributeId(rawDto.getAttributeId());
        newDto.setIndustryId(rawDto.getIndustryId());
        newDto.setIndustryName(rawDto.getIndustryName());
        newDto.setRegionId(rawDto.getRegionId());
        newDto.setRegionName(rawDto.getRegionName());
        newDto.setStructureId(rawDto.getStructureId());
        newDto.setAreaId(rawDto.getAreaId());
        newDto.setAreaName(rawDto.getAreaName());
        newDto.setClientCode(rawDto.getClientCode());
        newDto.setCode(rawDto.getCode());
        newDto.setParentId(rawDto.getParentId());
        newDto.setPLevel(rawDto.getPLevel());
        newDto.setTaxPayerNumber(rawDto.getTaxPayerNumber());

        // OrganizationDto newDto = CommonUtils.copyProperties(rawDto, new
        // OrganizationDto());
        // newDto.setDimensionId(dimensionId);
        // newDto.setDimensionName(dimensionDto.getName());
        // newDto.setDimensionValueId(rawDto.getBusinessUnitId());
        // newDto.setDimensionValueName(rawDto.getBusinessUnitName());
        // newDto.setStructureName(null);
        return newDto;
    }

    // private OrganizationDto filterOrgDtoNullValueForSelfDimension(OrganizationDto
    // orgDto) {
    // orgDto.setId(orgDto.getId() == null ? "" : orgDto.getId());
    // orgDto.setName(orgDto.getName() == null ? "" : orgDto.getName());
    // orgDto.setpLevel(orgDto.getpLevel() == null ? 0 : orgDto.getpLevel());
    // orgDto.setParentId(orgDto.getParentId() == null ? "" : orgDto.getParentId());
    // orgDto.setCode(orgDto.getCode() == null ? "" : orgDto.getCode());
    // orgDto.setClientCode(orgDto.getClientCode() == null ? "" :
    // orgDto.getClientCode());
    // orgDto.setBusinessUnitName(orgDto.getBusinessUnitName() == null ? "" :
    // orgDto.getBusinessUnitName());
    // orgDto.setAreaName(orgDto.getAreaName() == null ? "" : orgDto.getAreaName());
    // orgDto.setAreaId(orgDto.getAreaId() == null ? "" : orgDto.getAreaId());
    // orgDto.setStructureId(orgDto.getStructureId() == null ? "" :
    // orgDto.getStructureId());
    // orgDto.setRegionName(orgDto.getRegionName() == null ? "" :
    // orgDto.getRegionName());
    // orgDto.setRegionId(orgDto.getRegionId() == null ? "" : orgDto.getRegionId());
    // orgDto.setIndustryName(orgDto.getIndustryName() == null ? "" :
    // orgDto.getIndustryName());
    // orgDto.setIndustryId(orgDto.getIndustryId() == null ? "" :
    // orgDto.getIndustryId());
    // orgDto.setBusinessUnitId(orgDto.getBusinessUnitId() == null ? "" :
    // orgDto.getStructureName());
    // orgDto.setAttributeId(orgDto.getAttributeId() == null ? "" :
    // orgDto.getAttributeId());
    // return orgDto;
    // }

    public List<OrganizationDto> getOrganizationListByAreaId(String areaId, String attributeId) {

        List<AreaRegionDto> provinceRegionList = areaRegionMapper
                .selectByRegionLevelType(CommonConstants.REGION_LEVELTYPE_PROVINCE);

        List<Organization> organizationList = organizationMapper.selectByExample(null);
        List<OrganizationDto> allList = new ArrayList<>();
        organizationList.forEach(a -> {
            OrganizationDto organizationDto = new OrganizationDto();
            organizationDto.setId(a.getId());
            organizationDto.setParentId(a.getParentId());
            organizationDto.setName(a.getName());
            allList.add(organizationDto);
        });

        List<OrganizationDto> orgList = organizationMapper.selectIndBusUnitAreaOrgStrctReg(true, areaId,
                CommonConstants.REGION_LEVELTYPE_CITY);
        orgList.forEach(a -> {
            if (StringUtils.isNotEmpty(a.getParentName())) {
                List<AreaRegionDto> areaRegionList = new ArrayList<>();
                provinceRegionList.forEach(b -> {
                    if (StringUtils.equals(b.getRegionId(), a.getParentName()))
                        areaRegionList.add(b);
                });
                String provinceName = areaRegionList.isEmpty() ? null : areaRegionList.get(0).getRegionName();
                if (!StringUtils.equals(a.getRegionName(), provinceName)) {
                    a.setRegionName(provinceName + a.getRegionName());
                }
            }
            a.setParentId(getParentId(a, allList, orgList));
        });

        return orgList;
    }

    public AreaOrganizationStatistics getAreaStatistics() {
        AreaExample example = new AreaExample();
        example.createCriteria().andIsActiveEqualTo(true);
        List<Area> areaList = areaMapper.selectByExample(example);

        List<Area> firstRegionLevelList = areaList.stream().filter(sa -> sa.getParentId() == null).collect(toList());
        List<AreaRegionDto> provinceRegionList = areaRegionMapper
                .selectByRegionLevelType(AreaConstant.LevelTypeProvince);
        // 保证AreaId不为null
        provinceRegionList.stream().forEach(x -> x.setAreaId(Strings.sBlank(x.getAreaId())));

        OrganizationExample exampleOrg = new OrganizationExample();
        exampleOrg.createCriteria().andIsActiveEqualTo(true);
        List<OrganizationStatistics> orgList = organizationMapper.selectByExample(exampleOrg).stream()
                .map(this::convertToOrganizationStatistics).collect(toList());

        List<OrganizationDto> orgDtoList = orgList.stream().map(from -> {
            OrganizationDto to = new OrganizationDto();
            to.setAreaId(from.getAreaId());
            to.setId(from.getId());
            to.setName(from.getName());
            to.setBusinessUnitId(from.getBusinessUnitId());
            return to;
        }).collect(toList());

        List<DimensionValueOrgDto> dimensionValueOrgList = getDimensionValueOrgDtoList();

        Map<String, Integer> areaUserCount = roleService.getActiveUserRoleList(orgDtoList, dimensionValueOrgList,
                DimensionConstant.AreaId);

        List<AreaStatistics> areaRetList = new ArrayList<>();
        List<StatisticAttributeDisplayDto> rawAttrList = new ArrayList<>();
        statisticAttributeService.getStatisticAttributeListByDimensionId(DimensionConstant.AreaId, rawAttrList);

        for (Area item : firstRegionLevelList) {
            AreaStatistics areaStatics = new AreaStatistics();
            areaStatics.setId(item.getId());
            areaStatics.setName(item.getName());

            Map<String, Integer> tmpAttributeStatics = getAttributeStaticsByAreaId(item.getId(), orgList, rawAttrList,
                    areaUserCount, dimensionValueOrgList);
            areaStatics.setAttributeStatics(tmpAttributeStatics);

            List<String> provinceNameList = getProvinceNameList(item.getId(), provinceRegionList, areaList);
            areaStatics.setProvinceNameList(provinceNameList.stream().distinct().collect(toList()));
            areaRetList.add(areaStatics);
        }

        AreaOrganizationStatistics result = new AreaOrganizationStatistics();
        result.setAreaList(areaRetList);
        result.setAttributeList(rawAttrList);
        return result;
    }

    private List<String> getProvinceNameList(String areaId, List<AreaRegionDto> provinceList, List<Area> areaList) {
        // 找到城市列表
        List<AreaRegionDto> citys = provinceList.stream().filter(sa -> Objects.equals(areaId, sa.getAreaId()))
                .collect(toList());
        List<String> retList = new ArrayList<>();
        if (!Lang.isEmpty(citys)) {
            List<String> tmpList = citys.stream().map(AreaRegionDto::getRegionName).distinct().collect(toList());
            retList.addAll(tmpList);
        }
        List<Area> subArea = areaList.stream().filter(sa -> Objects.equals(areaId, sa.getParentId())).collect(toList());
        for (Area sub : subArea) {
            List<String> tempCitys = getProvinceNameList(sub.getId(), provinceList, areaList);
            if (!Lang.isEmpty(tempCitys))
                retList.addAll(tempCitys);

        }
        return retList;
    }

    private Map<String, Integer> getAttributeStaticsByAreaId(String areaId, List<OrganizationStatistics> allOrgList,
                                                             List<StatisticAttributeDisplayDto> rawAttrList, Map<String, Integer> areaUserCount,
                                                             List<DimensionValueOrgDto> dimensionValueOrgList) {
        int userCount = Optional.ofNullable(areaUserCount.get(areaId)).orElse(0);
        List<OrganizationStatistics> orgList = allOrgList.stream().filter(sa -> Objects.equals(areaId, sa.getAreaId()))
                .collect(toList());
        // 机构数,用户数,区域,事业部,行业,地区
        List<DimensionValueOrgDto> selfDimensionList = dimensionValueOrgList.stream().filter(
                (DimensionValueOrgDto sa) -> rawAttrList.stream().anyMatch((StatisticAttributeDisplayDto sb) -> Objects
                        .equals(sb.getBelongDimensionId(), sa.getDimensionId())))
                .collect(toList());
        Map<String, Integer> dic = new HashMap<>();
        for (StatisticAttributeDisplayDto item : rawAttrList) {
            if (AttributeTypeEnum.User.value().equals(item.getAttributeType())) {
                // 用户数
                item.setCount(userCount);
            } else if (AttributeTypeEnum.OrgSubChildren.value().equals(item.getAttributeType())) {
                // 机构数
                item.setCount((int) allOrgList.stream().filter(sa -> Objects.equals(areaId, sa.getAreaId())).count());
            } else if (AttributeTypeEnum.SelfDimension.value().equals(item.getAttributeType())) {
                // 自定义区域
                item.setCount((int) selfDimensionList.stream()
                        .filter(sa -> Objects.equals(item.getBelongDimensionId(), sa.getDimensionId()))
                        .map(DimensionValueOrgDto::getDimensionValueId).distinct().count());
            } else if (AttributeTypeEnum.Industry.value().equals(item.getAttributeType())) {
                // 行业
                item.setCount((int) orgList.stream().filter(sa -> sa.getIndustryId() != null)
                        .map(OrganizationStatistics::getIndustryId).distinct().count());
            } else if (AttributeTypeEnum.RegionId.value().equals(item.getAttributeType())) {
                // 行政地区
                item.setCount((int) orgList.stream().filter(sa -> sa.getCityId() != null)
                        .map(OrganizationStatistics::getCityId).distinct().count());
            } else if (AttributeTypeEnum.Area.value().equals(item.getAttributeType())) {
                // 区域维度
                item.setCount(1);
            } else if (AttributeTypeEnum.BusinessUnit.value().equals(item.getAttributeType())) {
                // 事业部
                item.setCount((int) orgList.stream().filter(sa -> sa.getBusinessUnitId() != null)
                        .map(OrganizationStatistics::getBusinessUnitId).distinct().count());
            } else if (AttributeTypeEnum.OrganizationStructure.value().equals(item.getAttributeType())) {
                item.setCount((int) orgList.stream().filter(sa -> sa.getStructureId() != null)
                        .map(OrganizationStatistics::getStructureId).distinct().count());
            }
            dic.put(item.getAttributeId(), item.getCount());
        }

        return dic;
    }

    private OrganizationStatistics convertToOrganizationStatistics(Organization from) {
        OrganizationStatistics to = new OrganizationStatistics();
        to.setUserCount(0);
        to.setName(from.getName());
        to.setId(from.getId());
        to.setBusinessUnitId(from.getBusinessUnitId());
        to.setCityId(from.getRegionId());
        to.setIndustryId(from.getIndustryId());
        to.setParentId(from.getParentId());
        to.setStructureId(from.getStructureId());
        to.setAreaId(from.getAreaId());
        return to;
    }

    /**
     */
    public OrgDto getOrgCustomDashbord(final String dimensionValueId, final String parentDimensionId,
                                       final String attributeId) {
        Assert.hasText(parentDimensionId, "Empty parentDimensionId");
        Assert.hasText(dimensionValueId, "Empty dimensionValueId");
        OrgDto orgDto = new OrgDto();
        List<OrganizationDto> orgDtoList = getOrgCustomDashbord$getOrgDtoList(dimensionValueId, parentDimensionId);
        List<OrganizationDto> orgDtoTempList = new ArrayList<>();

        List<OrganizationDto> orgTemp = getCustomDimensionOrgList();
        // join 两个变量:orgDtoList, orgTemp
        logger.debug("join 两个变量:orgDtoList, size[{}] orgTemp, size[{}]", orgDtoList.size(), orgTemp.size());
        // 代码理解:join的结果就是取orgTemp的字段,加上orgDtoTempList的name字段
        // 疑问:orgTemp的name字段与orgDtoTempList的name字段有什么区别?应该都是等价于Organization.name?
        List<OrgCustomDto> customOrgList = new ArrayList<>();
        for (OrganizationDto p : orgDtoList) {
            for (OrganizationDto d : orgTemp) {
                if (d.getId() != null && d.getId().equals(p.getId())) {
                    // on p.id equals d.id
                    OrgCustomDto tmp = new OrgCustomDto();
                    tmp.setAttributeId(d.getAttributeId());
                    tmp.setAttributeName(d.getAttributeName());
                    tmp.setDimensionId(d.getDimensionId());
                    tmp.setDimensionName(d.getDimensionName());
                    tmp.setDimensionValueId(d.getDimensionValueId());
                    tmp.setDimensionValueName(d.getDimensionValueName());
                    tmp.setOrgId(p.getId()); // 其实就是d.getId()
                    tmp.setOrgName(p.getName()); // 只有orgName使用了p.name
                    customOrgList.add(tmp);
                }
            }
        }
        orgDto.setOrgCustomDtoList(customOrgList);
        orgDto.setOrgCountList(new ArrayList<>());
        orgDto.setOrgDtoList(new ArrayList<>());

        // 如果是事业部
        if (attributeId.toLowerCase().equals(DimensionConstant.Attribute.BusinessUnitId)) {
            getOrgCustomDashbord$BusinessUnitId(orgDto, orgDtoList, orgDtoTempList);
        }
        // 如果是所属行业
        else if (attributeId.toLowerCase().equals(DimensionConstant.Attribute.IndustryId)) {
            getOrgCustomDashbord$IndustryId(orgDto, orgDtoList, orgDtoTempList);
        }
        // 如果是机构数
        else if (attributeId.toLowerCase().equals(DimensionConstant.Attribute.OrgSubChildrenId)) {
            getOrgCustomDashbord$OrgSubChildrenId(orgDto, orgDtoList, orgDtoTempList);
        }
        // 如果是机构层级
        else if (attributeId.toLowerCase().equals(DimensionConstant.Attribute.OrganizationStructureId)) {
            getOrgCustomDashbord$OrganizationStructureId(orgDto, orgDtoList, orgDtoTempList);
        }
        // 覆盖区域
        else if (attributeId.toLowerCase().equals(DimensionConstant.Attribute.AreaId)) {
            getOrgCustomDashbord$AreaId(orgDto, orgDtoList, orgDtoTempList);
        }
        // 如果是自定义属性,维度值的列表,多少维度,如产品维度,值为产品1,产品2,产品3 等
        else {
            getOrgCustomDashbord$DimensionValueId(attributeId, orgDto, orgDtoList, orgDtoTempList, orgTemp);
        }

        if (attributeId.toLowerCase().equals(DimensionConstant.Attribute.OrgSubChildrenId)) {
            List<OrgDisplayDto> tmplist = populateOrgLevel(orgDtoTempList);
            orgDto.setOrgDtoList(tmplist);
        } else {
            List<OrgDisplayDto> tmplist = orgDtoTempList.stream().map(this::convertToOrgDisplayDto).collect(toList());
            orgDto.setOrgDtoList(tmplist);
        }

        return orgDto;
    }

    public void getOrgCustomDashbord$DimensionValueId(final String attributeId, OrgDto orgDto,
                                                      List<OrganizationDto> orgDtoList, List<OrganizationDto> orgDtoTempList, List<OrganizationDto> orgTemp) {
        // 把orgDtoList LEFT JION orgTemp 放到customFilter变量
        List<OrgCustomDto> customFilter = new ArrayList<>();
        for (OrganizationDto p : orgDtoList) {
            for (OrganizationDto d : orgTemp) {
                OrganizationDto dtp = null;
                if (Objects.equals(d.getAttributeId(), attributeId) && Objects.equals(d.getId(), p.getId())) {
                    dtp = d;
                }
                OrgCustomDto joinItem = new OrgCustomDto();
                joinItem.setDimensionId(dtp == null ? "" : dtp.getDimensionId());
                joinItem.setDimensionName(dtp == null ? "" : dtp.getDimensionName());
                joinItem.setDimensionValueId(dtp == null ? "" : dtp.getDimensionValueId());
                joinItem.setDimensionValueName(dtp == null ? "" : dtp.getDimensionValueName());
                joinItem.setOrgId(p.getId());
                joinItem.setOrgName(p.getName());
                customFilter.add(joinItem);
            }
        }
        customFilter = customFilter.stream().distinct().collect(toList());

        List<Map<String, String>> dimensionValueList = customFilter.stream().map((x) -> {
            Map<String, String> map = new HashMap<>();
            map.put("id", x.getDimensionValueId());
            map.put("Name", x.getDimensionValueName());
            return map;
        }).distinct().collect(toList());

        for (Map<String, String> val : dimensionValueList) {
            OrganizationDto orgdto = new OrganizationDto();
            orgdto.setName(val.get("Name"));
            orgdto.setLevel(LevelConstant.FirstLevel);
            // 加入第0级节点
            orgDtoTempList.add(orgdto);

            // Group by id (DimensionValueId)
            // 代码分析:目的是为了找出OrgId的集合 groupList.item.getOrgId
            List<OrgCustomDto> groupList = customFilter.stream()
                    .filter(x -> Objects.equals(val.get("id"), x.getDimensionValueId())).collect(toList());

            // 代码分析:通过OrgId的集合,把原始的Org集合选出来
            groupList.forEach(g -> {
                orgDtoList.stream().filter(s -> Objects.equals(s.getId(), g.getOrgId())).forEach(r -> {
                    r.setLevel(LevelConstant.FirstLevel + 1);
                    orgDtoTempList.add(r);
                });
            });

            boolean noneMatch = orgDto.getOrgCountList().stream()
                    .noneMatch(x -> Objects.equals(val.get("id"), x.getId()));
            if (noneMatch) {
                OrgCountDto org = new OrgCountDto();
                org.setId(val.get("id"));
                org.setName(val.get("Name"));
                org.setCount((int) customFilter.stream()
                        .filter(s -> Objects.equals(val.get("id"), s.getDimensionValueId())).count());
                orgDto.getOrgCountList().add(org);
            }
        }
    }

    private List<OrgDisplayDto> populateOrgLevel(List<OrganizationDto> orgDtoList) {
        List<OrgDisplayDto> displayList = new ArrayList<>();

        // FIXME C#中可能有Bug, SQL字段少了IsActive, 先照原样复制过来
        // SELECT id, ParentId from Organization
        List<OrganizationDto> orgList = organizationMapper.selectOnlyIdAndParentId();
        for (OrganizationDto item : orgDtoList) {
            if (item.getParentId() == null)
                continue;

            // 找到了parentId
            boolean foundParentId = orgDtoList.stream().anyMatch(x -> item.getParentId().equals(x.getId()));
            if (foundParentId)
                continue;

            // 重新设置ParentId
            item.setParentId(getParentId(item, orgList, orgDtoList));
        }

        List<OrganizationDto> topList = orgDtoList.stream().filter(p -> {
            return orgDtoList.stream().noneMatch(sa -> {
                return Objects.equals(sa.getId(), p.getParentId());
            });
        }).collect(toList());

        for (OrganizationDto top : topList) {
            top.setLevel(LevelConstant.FirstLevel);
            OrgDisplayDto display = convertToOrgDisplayDto(top);
            displayList.add(display);
            List<OrgDisplayDto> subList = getChildren(top, orgDtoList);
            displayList.addAll(subList);
        }

        return displayList;
    }

    private List<OrgDisplayDto> getChildren(OrganizationDto current, List<OrganizationDto> orgList) {
        List<OrgDisplayDto> retList = new ArrayList<>();
        List<OrganizationDto> subList = orgList.stream().filter(sa -> Objects.equals(sa.getParentId(), current.getId()))
                .collect(toList());
        subList.forEach(item -> {
            item.setLevel(LevelConstant.FirstLevel + 1);
            retList.add(convertToOrgDisplayDto(item));
            List<OrgDisplayDto> children = getChildren(item, orgList);
            if (Lang.isEmpty(children)) {
                // 疑问: C#代码中,为什么把level设为0?
                item.setLevel(LevelConstant.FirstLevel);
            }
            retList.addAll(children);
        });

        return retList;
    }

    private String getParentId(OrganizationDto current, List<OrganizationDto> allList,
                               List<OrganizationDto> orgDtoList) {
        if (current.getParentId() == null)
            return null;

        // 这个是为了处理脏数据,那种Id 和 ParentId 是一样的情况
        if (current.getParentId().equals(current.getId()))
            return null;

        // 代码理解:从全量中找到父节点
        OrganizationDto findParent = allList.stream().filter(sa -> current.getParentId().equals(sa.getId())).findFirst()
                .orElse(null);

        // 处理脏数据
        if (findParent == null)
            return null;

        if (BooleanUtils.isTrue(findParent.getIsActive())) {
            // 代码理解:从目标集合中找到这个节点
            OrganizationDto parent = orgDtoList.stream().filter(sa -> Objects.equals(sa.getId(), findParent.getId()))
                    .findFirst().orElse(null);
            if (parent != null)
                return parent.getId();
        }
        return getParentId(findParent, allList, orgDtoList);
    }

    private OrgDisplayDto convertToOrgDisplayDto(OrganizationDto from) {
        OrgDisplayDto to = copyProperties(from, new OrgDisplayDto());
        to.setPLevel(from.getPLevel());
        to.setOrgName(from.getName());
        to.setOrgId(from.getId());
        to.setPLevel(Optional.ofNullable(to.getPLevel()).orElse(0));
        to.setLevel(Optional.ofNullable(to.getLevel()).orElse(0));
        to.setSubsidiaryCount(Optional.ofNullable(to.getSubsidiaryCount()).orElse(0));
        to.setAreaCount(Optional.ofNullable(to.getAreaCount()).orElse(0));
        return to;
    }

    /**
     * 从getOrgCustomDashbord抽取出来的方法
     */
    private void getOrgCustomDashbord$OrgSubChildrenId(OrgDto orgDto, List<OrganizationDto> orgDtoList,
                                                       List<OrganizationDto> orgDtoTempList) {
        // 删除无用的dimensionValueList变量
        orgDtoTempList.clear();
        // C#的代码是改变指针,这里改为clear, addAll
        orgDtoTempList.addAll(orgDtoList);
        OrgCountDto org = new OrgCountDto();
        org.setName(OrganizationMessage.OrganizationCount);
        // 统计businessUnitId数量
        org.setCount(orgDtoList.size());
        orgDto.getOrgCountList().add(org);
    }

    /**
     * 从getOrgCustomDashbord抽取出来的方法
     */
    private void getOrgCustomDashbord$AreaId(OrgDto orgDto, List<OrganizationDto> orgDtoList,
                                             List<OrganizationDto> orgDtoTempList) {
        // 找出IndustryId的列表,去重复
        List<Map<String, String>> dimensionValueList = orgDtoList.stream().map((OrganizationDto x) -> {
            Map<String, String> map = new HashMap<>();
            map.put("id", x.getAreaId());
            map.put("Name", x.getAreaName());
            return map;
        }).distinct().collect(toList());

        // 遍历BU Id的列表
        for (Map<String, String> val : dimensionValueList) {
            OrganizationDto orgdto = new OrganizationDto();
            orgdto.setName(val.get("Name"));
            orgdto.setLevel(LevelConstant.FirstLevel);
            // 加入第0级节点
            orgDtoTempList.add(orgdto);

            // 找出这个BU对应的OrganizationDto列表
            List<OrganizationDto> groupList = orgDtoList.stream()
                    .filter(x -> Objects.equals(val.get("id"), x.getAreaId())).collect(toList());

            groupList.forEach((OrganizationDto r) -> {
                r.setLevel(LevelConstant.FirstLevel + 1);
                // 加入第1级节点
                orgDtoTempList.add(r);
            });

            boolean noSuchItemById = orgDto.getOrgCountList().stream()
                    .noneMatch(x -> Objects.equals(val.get("id"), x.getId()));
            if (noSuchItemById) {
                OrgCountDto org = new OrgCountDto();
                org.setId(val.get("id"));
                org.setName(val.get("Name"));
                // 统计businessUnitId数量
                org.setCount(
                        (int) orgDtoList.stream().filter(x -> Objects.equals(val.get("id"), x.getAreaId())).count());
                orgDto.getOrgCountList().add(org);
            }
        }
    }

    /**
     * 从getOrgCustomDashbord抽取出来的方法
     */
    private void getOrgCustomDashbord$OrganizationStructureId(OrgDto orgDto, List<OrganizationDto> orgDtoList,
                                                              List<OrganizationDto> orgDtoTempList) {
        // 找出IndustryId的列表,去重复
        List<Map<String, String>> dimensionValueList = orgDtoList.stream().map((OrganizationDto x) -> {
            Map<String, String> map = new HashMap<>();
            map.put("id", x.getStructureId());
            map.put("Name", x.getStructureName());
            return map;
        }).distinct().collect(toList());

        // 遍历BU Id的列表
        for (Map<String, String> val : dimensionValueList) {

            OrganizationDto orgdto = new OrganizationDto();
            orgdto.setName(val.get("Name"));
            orgdto.setLevel(LevelConstant.FirstLevel);
            // 加入第0级节点
            orgDtoTempList.add(orgdto);

            // 找出这个BU对应的OrganizationDto列表
            List<OrganizationDto> groupList = orgDtoList.stream()
                    .filter(x -> Objects.equals(val.get("id"), x.getStructureId())).collect(toList());

            groupList.forEach((OrganizationDto r) -> {
                r.setLevel(LevelConstant.FirstLevel + 1);
                // 加入第1级节点
                orgDtoTempList.add(r);
            });

            boolean noSuchItemById = orgDto.getOrgCountList().stream()
                    .noneMatch(x -> Objects.equals(val.get("id"), x.getId()));
            if (noSuchItemById) {
                OrgCountDto org = new OrgCountDto();
                org.setId(val.get("id"));
                org.setName(val.get("Name"));
                // 统计businessUnitId数量
                org.setCount((int) orgDtoList.stream().filter(x -> Objects.equals(val.get("id"), x.getStructureId()))
                        .count());
                orgDto.getOrgCountList().add(org);
            }
        }
    }

    /**
     * 从getOrgCustomDashbord抽取出来的方法
     */
    private void getOrgCustomDashbord$IndustryId(OrgDto orgDto, List<OrganizationDto> orgDtoList,
                                                 List<OrganizationDto> orgDtoTempList) {
        // 找出IndustryId的列表,去重复
        List<Map<String, String>> dimensionValueList = orgDtoList.stream().map((OrganizationDto x) -> {
            Map<String, String> map = new HashMap<>();
            map.put("id", x.getIndustryId());
            map.put("Name", x.getIndustryName());
            return map;
        }).distinct().collect(toList());

        // 遍历BU Id的列表
        for (Map<String, String> val : dimensionValueList) {

            OrganizationDto orgdto = new OrganizationDto();
            orgdto.setName(val.get("Name"));
            orgdto.setLevel(LevelConstant.FirstLevel);
            // 加入第0级节点
            orgDtoTempList.add(orgdto);

            // 找出这个BU对应的OrganizationDto列表
            List<OrganizationDto> groupList = orgDtoList.stream()
                    .filter(x -> Objects.equals(val.get("id"), x.getIndustryId())).collect(toList());

            groupList.forEach((OrganizationDto r) -> {
                r.setLevel(LevelConstant.FirstLevel + 1);
                // 加入第1级节点
                orgDtoTempList.add(r);
            });

            boolean noSuchItemById = orgDto.getOrgCountList().stream()
                    .noneMatch(x -> Objects.equals(val.get("id"), x.getId()));
            if (noSuchItemById) {
                OrgCountDto org = new OrgCountDto();
                org.setId(val.get("id"));
                org.setName(val.get("Name"));
                // 统计businessUnitId数量
                org.setCount((int) orgDtoList.stream().filter(x -> Objects.equals(val.get("id"), x.getIndustryId()))
                        .count());
                orgDto.getOrgCountList().add(org);
            }
        }
    }

    /**
     * 从getOrgCustomDashbord抽取出来的方法
     */
    private void getOrgCustomDashbord$BusinessUnitId(OrgDto orgDto, List<OrganizationDto> orgDtoList,
                                                     List<OrganizationDto> orgDtoTempList) {
        // 找出BU Id的列表,去重复
        List<Map<String, String>> dimensionValueList = orgDtoList.stream().map((OrganizationDto x) -> {
            Map<String, String> map = new HashMap<>();
            map.put("id", x.getBusinessUnitId());
            map.put("Name", x.getBusinessUnitName());
            return map;
        }).distinct().collect(toList());

        // 遍历BU Id的列表
        for (Map<String, String> val : dimensionValueList) {

            OrganizationDto orgdto = new OrganizationDto();
            orgdto.setName(val.get("Name"));
            orgdto.setLevel(LevelConstant.FirstLevel);
            // 加入第0级节点
            orgDtoTempList.add(orgdto);

            // 找出这个BU对应的OrganizationDto列表
            List<OrganizationDto> groupList = orgDtoList.stream()
                    .filter(x -> Objects.equals(val.get("id"), x.getBusinessUnitId())).collect(toList());

            groupList.forEach((OrganizationDto r) -> {
                r.setLevel(LevelConstant.FirstLevel + 1);
                // 加入第1级节点
                orgDtoTempList.add(r);
            });

            boolean noSuchItemById = orgDto.getOrgCountList().stream()
                    .noneMatch(x -> Objects.equals(val.get("id"), x.getId()));
            if (noSuchItemById) {
                OrgCountDto org = new OrgCountDto();
                org.setId(val.get("id"));
                org.setName(val.get("Name"));
                // 统计businessUnitId数量
                org.setCount((int) orgDtoList.stream().filter(x -> Objects.equals(val.get("id"), x.getBusinessUnitId()))
                        .count());
                orgDto.getOrgCountList().add(org);
            }
        }
    }

    /**
     * 从getOrgCustomDashbord抽取出来的方法
     */
    private List<OrganizationDto> getOrgCustomDashbord$getOrgDtoList(final String dimensionValueId,
                                                                     final String parentDimensionId) {
        List<OrganizationDto> orgDtoList = null;

        if (DimensionConstant.OrgSubChildrenId.equals(parentDimensionId)) {
            // 如果是机构
            // 查找所有该父机构下的所有子机构
            List<OrganizationDto> allOrgList = getAllOrgList();
            String parentOrgId = dimensionValueId;
            // orgList 所有的子机构的Id List
            List<String> orgList = getChildrenOrgIdToList(parentOrgId, allOrgList).stream()
                    .filter(x -> !parentOrgId.equals(x)).collect(toList());

            // 然后用所有的子机构的Id List在内存中条件过滤
            orgDtoList = getOrgDimensionMappingForDimension(parentDimensionId).stream()
                    .filter(x -> orgList.contains(x.getId())).collect(toList());
        } else {
            // 如果不是机构
            // getOrgDimensionMappingForDimension查出的是全量的数据
            // 然后用dimensionId和dimensionValueId两个字段在内存中条件过滤
            orgDtoList = getOrgDimensionMappingForDimension(
                    parentDimensionId)
                    .stream()
                    .filter(organizationDto -> (parentDimensionId.equals(organizationDto.getDimensionId())
                            && dimensionValueId.equals(organizationDto.getDimensionValueId())))
                    .collect(toList());
        }
        // 去除机构为空的值
        orgDtoList.removeIf(x -> Strings.isBlank(x.getId()));
        return orgDtoList;
    }

    /**
     * 获取维度的名称,维度值的名称
     */
    public OrgCustomDto getDimensionValueName(String dimensionId, String dimensionValueId) {
        OrgCustomDto customDto = new OrgCustomDto();
        DimensinTypeOrgDto dimensionDto = dimensionService.getDimensionById(dimensionId);
        Integer dimensionType = dimensionDto.getDimensionType();
        customDto.setDimensionName(dimensionDto.getName());
        if (DimensionTypeEnum.BusinessUnit.value().equals(dimensionType)) {
            BusinessUnit value = dimensionValueId != null ? businessUnitMapper.selectByPrimaryKey(dimensionValueId)
                    : null;
            if (value != null) {
                customDto.setDimensionValueName(value.getName());
            }
        } else if (DimensionTypeEnum.OrganizationStructure.value().equals(dimensionType)) {
            OrganizationStructure value = dimensionValueId != null
                    ? organizationStructureMapper.selectByPrimaryKey(dimensionValueId)
                    : null;
            if (value != null) {
                customDto.setDimensionValueName(value.getName());
            }
        } else if (DimensionTypeEnum.SelfDimension.value().equals(dimensionType)) {
            DimensionValue value = dimensionValueId != null ? dimensionValueMapper.selectByPrimaryKey(dimensionValueId)
                    : null;
            if (value != null) {
                customDto.setDimensionValueName(value.getName());
            }
        }
        return customDto;
    }

    @SuppressWarnings({"rawtypes", "deprecation"})
    public OperationResultDto disableOrgs(List<String> orgIds) {
        try {
            List<OperationLogDto> logList = new ArrayList<>();
            for (String orgId : orgIds) {
                Organization rootOrg = orgId != null ? organizationMapper.selectByPrimaryKey(orgId) : null;
                Assert.notNull(rootOrg, "rootOrg is null");
                if (rootOrg.getIsActive()) {
                    rootOrg.setIsActive(false);
                    organizationMapper.updateByPrimaryKey(rootOrg);
                    OperationLogDto opLog = new OperationLogDto();
                    opLog.setAction(OperationAction.Update.value());
                    opLog.setOperationContent(LogMessage.IsActive);
                    opLog.setOperationObject(rootOrg.getName());
                    opLog.setOriginalState(BooleanUtils.isTrue(rootOrg.getIsActive()) ? "False" : "True");
                    opLog.setUpdateState(BooleanUtils.isTrue(rootOrg.getIsActive()) ? "True" : "False");
                    opLog.setModule(OperationModule.Organization.value());
                    opLog.setComment("");
                    opLog.setLogType(OperateLogType.OperationLogOrganization.value());
                    logList.add(opLog);
                }
            }
            operationLogService.addOperationLogList(logList);
            return new OperationResultDto(true);
        } catch (Exception ex) {
            logger.error("DisableOrgs出错了:" + ex, ex);
            logger.error("标记回滚, ready to call setRollbackOnly");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new OperationResultDto(false, ex.getMessage());
        }
    }

    @SuppressWarnings({"rawtypes"})
    public OperationResultDto enableOrgs(String orgId) {
        Organization curOrg = orgId != null ? organizationMapper.selectByPrimaryKey(orgId) : null;
        if (curOrg == null) {
            return new OperationResultDto(false, OrganizationMessage.NotFindOrgEnable);
        } else {
            if (!curOrg.getIsActive()) {
                curOrg.setIsActive(true);
                organizationMapper.updateByPrimaryKey(curOrg);
                OperationLogDto opLog = new OperationLogDto();
                opLog.setAction(OperationAction.Update.value());
                opLog.setOperationContent(LogMessage.IsActive);
                opLog.setOperationObject(curOrg.getName());
                opLog.setOriginalState(LogMessage.Disable);
                opLog.setUpdateState(LogMessage.Enable);
                opLog.setIp("");
                opLog.setModule(OperationModule.Organization.value());
                opLog.setComment("");
                opLog.setLogType(OperateLogType.OperationLogOrganization.value());
                operationLogService.addOperationLog(opLog);
            }
            return new OperationResultDto(true);
        }
    }

    public OrganizationDto getSingleOrgByOrgId(String orgId) {
        OrganizationDto result = organizationMapper.getSingleOrgByOrgIdToOrgDto(orgId).stream().findFirst()
                .orElse(null);
        Assert.notNull(result, "result is null");
        result.setLevel(result.getLevel() == null ? 0 : result.getLevel());
        result.setIsSystemDimension(result.getIsSystemDimension() == null ? false : result.getIsSystemDimension());

        // 查询机构账套
        List<EnterpriseAccountSetOrgDto> query1 = enterpriseAccountSetOrgMapper.getSingleOrgByOrgIdToEASODto(orgId);
        for (EnterpriseAccountSetOrgDto p : query1) {
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM");
            p.setExpiredDateStr(p.getExpiredDate() == null ? "" : formatter.format(p.getExpiredDate()));
            p.setEffectiveDateStr(p.getEffectiveDate() == null ? "" : formatter.format(p.getEffectiveDate()));
        }
        result.setEnterpriseAccountSetOrgList(query1);
        // 查询机构服务
        List<ServiceType> serviceType = serviceTypeMapper.selectByExample(null);
        List<OrganizationServiceTemplateGroupDto> query2 = organizationServiceTemplateGroupMapper
                .getSingleOrgByOrgIdToOSTGDto(orgId);
        for (OrganizationServiceTemplateGroupDto mapping : query2) {
            ServiceType st = serviceType.stream().filter(n -> Objects.equals(n.getId(), mapping.getServiceTypeId()))
                    .findFirst().orElse(null);
            if (st != null) {
                mapping.setServiceTypeName(st.getName());
            }
        }
        result.setOrganizationServiceTemplateGroupList(query2);
        if (result.getParentId() == null) {
            result.setParentName("");
        } else {
            Organization tParent = organizationMapper.selectByExample(null).stream()
                    .filter(sa -> Objects.equals(sa.getId(), result.getParentId())).findFirst().orElse(null);
            Assert.notNull(tParent, "tParent is null");
            result.setParentName(tParent.getName());
        }
        result.setDimensionValueOrgList(dimensionService.getAllDimensionOrgListByOrgId(result.getId()));
        return result;
    }

    public Boolean codeUniqueValidate(OrganizationValidateDto validateDto) {
        String innerId = Strings.isBlank(validateDto.getId()) ? "" : validateDto.getId().trim();
        String innerCode = Strings.isBlank(validateDto.getValue()) ? "" : validateDto.getValue().trim();
        return Strings.isBlank(innerCode)
                || organizationMapper.countForCodeUniqueValidate(innerId, innerCode).equals(0);
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public OperationResultDto<Object> addOrg(OrganizationDto orgDto) {
        try {
            OperationResultDto result = checkExist(orgDto);
            if (result != null && !BooleanUtils.isTrue(result.getResult())) {
                return new OperationResultDto(result.getResult(), result.getResultMsg());
            }
            if (Objects.equals(orgDto.getParentId(), OrganizationConstant.NoParentId)) {
                orgDto.setParentId(null);
                orgDto.setPLevel(0);
            } else {
                // 机构添加层级
                Organization query = null;
                query = orgDto.getParentId() != null ? organizationMapper.selectByPrimaryKey(orgDto.getParentId())
                        : null;
                if (query != null) {
                    orgDto.setPLevel(query.getpLevel() + 1);
                }
            }

            orgDto.setId(CommonUtils.getUUID());
            Date now = new Date();
            orgDto.setCreateTime(now);
            orgDto.setUpdateTime(now);

            OrganizationValidateDto vailOrgDto = new OrganizationValidateDto();
            vailOrgDto.setId(orgDto.getId());
            vailOrgDto.setValue(orgDto.getCode());

            if (!codeUniqueValidate(vailOrgDto)) {
                return new OperationResultDto(false, OrganizationMessage.OrgNameOrCodeIsExiste);
            }

            vailOrgDto = new OrganizationValidateDto();
            vailOrgDto.setId(orgDto.getId());
            vailOrgDto.setValue(orgDto.getTaxPayerNumber());

            if (!taxPayerNumberUniqueValidate(vailOrgDto)) {
                return new OperationResultDto(false, OrganizationMessage.OrgNameOrCodeTaxPaymentNoIsExist);
            }

            Organization org = copyProperties(orgDto, new Organization());
            org.setpLevel(orgDto.getPLevel());
            organizationMapper.insert(org);
            OperationResultDto<Object> validateSetRet = validateEnterpriseAccountSetDateTimeOverlap(
                    orgDto.getEnterpriseAccountSetOrgList());
            if (!validateSetRet.getResult()) {
                logger.error("标记回滚, ready to call setRollbackOnly");
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return validateSetRet;
            }

            // 添加账套
            for (EnterpriseAccountSetOrgDto p : orgDto.getEnterpriseAccountSetOrgList()) {
                EnterpriseAccountSetOrg enterpriseAccountSetOrg = new EnterpriseAccountSetOrg();
                enterpriseAccountSetOrg.setId(CommonUtils.getUUID());
                enterpriseAccountSetOrg.setEnterpriseAccountSetId(p.getEnterpriseAccountSetId());
                enterpriseAccountSetOrg.setOrganizationId(orgDto.getId());
                if (!Strings.isEmpty(p.getEffectiveDateStr())) {
                    enterpriseAccountSetOrg.setEffectiveDate(DateTimeFormat.forPattern("yyyy-MM-dd")
                            .parseDateTime(p.getEffectiveDateStr() + "-01").toDate());
                    p.setEffectiveDate(DateTimeFormat.forPattern("yyyy-MM-dd")
                            .parseDateTime(p.getEffectiveDateStr() + "-01").toDate());
                }

                if (!Strings.isEmpty(p.getExpiredDateStr())) {
                    enterpriseAccountSetOrg.setExpiredDate(DateTimeFormat.forPattern("yyyy-MM-dd")
                            .parseDateTime(p.getExpiredDateStr() + "-01").plusMonths(1).minusDays(1).toDate());
                    p.setExpiredDate(DateTimeFormat.forPattern("yyyy-MM-dd")
                            .parseDateTime(p.getExpiredDateStr() + "-01").plusMonths(1).minusDays(1).toDate());
                }
                enterpriseAccountSetOrgMapper.insert(enterpriseAccountSetOrg);
            }

            // 添加服务
            // For VAT, update Rule Engine tables after updating
            // OrganizationServiceTemplateGroup
            // .NET中定义了以下变量,但未被使用,故在此处注释 defaultRule, reportRules
            OrganizationServiceTemplateGroupDto vatSetting = orgDto.getOrganizationServiceTemplateGroupList().stream()
                    .filter(t -> ServiceTypeEnum.VAT.toString().equals(t.getServiceTypeId())).findFirst().orElse(null);
            if (vatSetting != null) { // If currently no rule and new rule should be added
                TemplateGroup templateGrp = vatSetting.getTemplateGroupId() != null
                        ? templateGroupMapper.selectByPrimaryKey(vatSetting.getTemplateGroupId())
                        : null;
                // In organization module tax payer type is 1&2 while 0&1 in rule engine
                Integer newTaxPayerType = (templateGrp != null && templateGrp.getPayTaxType() != null)
                        ? templateGrp.getPayTaxType() - 1
                        : VatTaxPayerTypeEnum.General.value();
                TaxPayerReportRule newRule = new TaxPayerReportRule();
                newRule.setId(distributedIdService.nextId());
                newRule.setIsDefault(false);
                newRule.setOrganizationId(orgDto.getId());
                newRule.setTemplateGroupId(vatSetting.getTemplateGroupId());
                newRule.setTaxPayerType(newTaxPayerType); // Use tax payer type related to template group
                newRule.setCreateTime(now);
                newRule.setUpdateTime(now);
                taxPayerReportRuleMapper.insert(newRule);
            }
            for (OrganizationServiceTemplateGroupDto p : orgDto.getOrganizationServiceTemplateGroupList()) {
                OrganizationServiceTemplateGroup orgServiceTempGroup = new OrganizationServiceTemplateGroup();
                orgServiceTempGroup.setId(distributedIdService.nextId());
                orgServiceTempGroup.setOrganizationId(orgDto.getId());
                orgServiceTempGroup.setServiceTypeId(p.getServiceTypeId());
                orgServiceTempGroup.setTemplateGroupId(p.getTemplateGroupId());
                organizationServiceTemplateGroupMapper.insert(orgServiceTempGroup);
            }

            // CopyModelTree(orgDto);//__restoreroy__

            addOrgSelfDimensionList(orgDto);
            // C#中的内部类CommonLogParams 在JAVA中已经被合并到OperationLogDto中
            UpdateLogParams tempCommonLogParms = new UpdateLogParams();
            tempCommonLogParms.setOperationModule(Organization.value());
            tempCommonLogParms.setComment(AddOrganization);
            tempCommonLogParms.setOperateLogType(OperationLogOrganization.value());
            tempCommonLogParms.setOperationContent(org.getName());
            tempCommonLogParms.setOperationAction(OperationAction.New.value());
            tempCommonLogParms.setOperationObject(orgDto.getName());
            tempCommonLogParms.setUpdateState("");
            tempCommonLogParms.setOriginalState("");
            operationLogService.addOrDeleteDataAddLog(tempCommonLogParms);
            return new OperationResultDto(true);
        } catch (Exception e) {
            logger.error("addOrg出错:" + e, e);
            logger.error("标记回滚, ready to call setRollbackOnly");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new OperationResultDto(false, CommonFail + e.getMessage());
        }
    }

    // C#中形参userName在函数中未被使用,故删除
    private void addOrgSelfDimensionList(OrganizationDto orgDto) {
        if (orgDto.getDimensionValueOrgList() == null || orgDto.getDimensionValueOrgList().isEmpty()) {
            return;
        }
        List<DimensionValueOrg> addList = new ArrayList<>();
        // C#中的内部类CommonLogParams 在JAVA中已经被合并到OperationLogDto中
        // C#中进行联合查询获取到DimensionValue和Dimension的表,但无调用。 dimensionLogList未被使用,故将其删除
        for (DimensionValueOrgDto item : orgDto.getDimensionValueOrgList()) {
            DimensionValueOrg dvOrg = new DimensionValueOrg();
            // C#中下文UpdateTime 与 CreateTime在数据库中并无对应字段,故删除
            dvOrg.setOrganizationId(orgDto.getId());
            dvOrg.setId(CommonUtils.getUUID());
            dvOrg.setDimensionValueId(item.getDimensionValueId());
            addList.add(dvOrg);
        }
        if (!addList.isEmpty()) {
            addList.stream().forEach(x -> dimensionValueOrgMapper.insert(x));
        }

    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public OperationResultDto<Object> validateEnterpriseAccountSetDateTimeOverlap(
            List<EnterpriseAccountSetOrgDto> list) {
        if (list != null && !list.isEmpty()) {
            for (EnterpriseAccountSetOrgDto p : list) {
                p.setEffectiveDate(null);
                p.setExpiredDate(null);
                if (Strings.isNotBlank(p.getEffectiveDateStr())) {
                    p.setEffectiveDate(DateTimeFormat.forPattern("yyyy-MM-dd")
                            .parseDateTime(p.getEffectiveDateStr() + "-01").toDate());
                }
                if (Strings.isNotBlank(p.getExpiredDateStr())) {
                    p.setExpiredDate(DateTimeFormat.forPattern("yyyy-MM-dd")
                            .parseDateTime(p.getExpiredDateStr() + "-01").plusMonths(1).minusDays(1).toDate());
                }
            }
            if (list.stream().anyMatch(sa -> sa.getEffectiveDate().after(sa.getExpiredDate()))) {
                return new OperationResultDto(false, EffectiveDateAreaProblem);
            }

            List<EnterpriseAccountSetOrgDto> overlapList = new ArrayList<>();
            if (commonService.isOrganizationDateTimeOverlap(list)) {
                list.stream().filter(sa -> sa.getOverlapList() != null && !sa.getOverlapList().isEmpty())
                        .forEach(s -> overlapList.add(s));
            }
            if (!overlapList.isEmpty()) {
                return new OperationResultDto(false, EnterpriseAccountSetOrgDateTimeOverlap, overlapList);
            }
            // 一年之内不能设置两个一样的账套,即:不能设置这种,账套A,2017年1月到3月,账套A,2017年4月到5月
            List<String> acountList = list.stream().map(EnterpriseAccountSetOrgDto::getEnterpriseAccountSetId)
                    .distinct().collect(Collectors.toList());
            for (String accountId : acountList) {
                List<EnterpriseAccountSetOrgDto> tempList = list.stream()
                        .filter(sa -> Strings.equals(sa.getEnterpriseAccountSetId(), accountId))
                        .collect(Collectors.toList());
                if (!CommonUtils.validateOnlyOncePerYear(tempList)) {
                    return new OperationResultDto(false,
                            EnterpriseAccountSetOrgMessage.EnterpriseAccountSetOrgOnlyOncePerYear);
                }
            }
        }
        return new OperationResultDto(true);
    }

    @SuppressWarnings("rawtypes")
    private OperationResultDto checkExist(OrganizationDto orgDto) {
        Assert.notNull(orgDto, "orgDto null point error");
        Organization queryRoot = null;
        if (orgDto.getParentId() != null) {
            OrganizationExample example = new OrganizationExample();
            Criteria criteria = example.createCriteria();
            criteria.andClientCodeEqualTo(orgDto.getClientCode());
            if (orgDto.getId() != null) {
                criteria.andIdNotEqualTo(orgDto.getId());
            }
            queryRoot = organizationMapper.selectByExample(example).stream().findFirst().orElse(null);
        }
        if (queryRoot != null && orgDto.getId() != null && Strings.equals(orgDto.getId(), CommonConstants.EMPTY_UUID)) {
            return new OperationResultDto(false, OrganizationMessage.ClientCodeIsExist);
        }
        OperationResultDto operationResult = checkOrgNameOrOrgCode(orgDto);
        if (operationResult.getResult()) {
            operationResult = checkCodeTaxPaymentNo(orgDto);
        }
        return operationResult;
    }

    @SuppressWarnings("rawtypes")
    private OperationResultDto checkCodeTaxPaymentNo(OrganizationDto orgDto) {

        OrganizationExample example = new OrganizationExample();
        Criteria criteria = example.createCriteria();
        criteria.andNameEqualTo(orgDto.getName()).andCodeEqualTo(orgDto.getCode());
        if (orgDto.getTaxPayerNumber() != null) {
            criteria.andTaxPayerNumberEqualTo(orgDto.getTaxPayerNumber());
        } else {
            criteria.andTaxPayerNumberIsNull();
        }
        if (orgDto.getId() != null) {
            criteria.andIdNotEqualTo(orgDto.getId());
        }
        Organization query = organizationMapper.selectByExample(example).stream().findFirst().orElse(null);
        if (query != null) {
            return new OperationResultDto(false, OrganizationMessage.OrgNameOrCodeTaxPaymentNoIsExist);
        }
        return new OperationResultDto(true);
    }

    @SuppressWarnings("rawtypes")
    public OperationResultDto updateOrgToDimension(String dimensionValueId, String parentDimensionId,
                                                   List<OrgBasicDto> orgList) {
        if (orgList == null || dimensionValueId == null || parentDimensionId == null) {
            throw new ApplicationException(CommonConstants.JSONNULLOBJECT);
        }
        String dimensionName = dimensionService.getDimensionById(parentDimensionId).getName();
        // 事业部,更新机构表
        if (DimensionConstant.BusinessUnitId.equalsIgnoreCase(parentDimensionId)) {
            for (OrgBasicDto model : orgList) {
                Organization old = organizationMapper.selectByPrimaryKey(model.getId());
                if (old == null) {
                    throw new ApplicationException(CommonConstants.JSONNULLOBJECT);
                }
                Organization copy = CommonUtils.copyProperties(old, new Organization());
                old.setBusinessUnitId(dimensionValueId);
                logger.debug("Start to update organization [ {} ]", old.getId());
                organizationMapper.updateByPrimaryKey(old);
                UpdateLogParams updateLogParams = new UpdateLogParams();
                updateLogParams.setOperateLogType(OperateLogType.OperationLogOrganization.value());
                updateLogParams.setComment("");
                updateLogParams.setOperationModule(OperationModule.BasicDataBusinessUnit.value());
                updateLogParams.setOperationContent(dimensionName);
                updateLogParams.setOriginalState(copy);
                updateLogParams.setUpdateState(old);
                updateLogParams.setOperationObject(model.getName());
                updateLogParams.setOperationAction(OperationAction.Update.value());
                operationLogService.updateDataAddLog(updateLogParams);
            }
        } else if (DimensionConstant.OrgSubChildrenId.equalsIgnoreCase(parentDimensionId)) {

        } else if (DimensionConstant.AreaId.equalsIgnoreCase(parentDimensionId)) {
            List<UpdateLogParams> logList = new ArrayList<>();
            List<NameDto> areaNameDtoList = areaMapper.selectByExample(new AreaExample()).stream()
                    .map(sa -> CommonUtils.copyProperties(sa, new NameDto())).collect(Collectors.toList());
            NameDto newArea = areaNameDtoList.stream().filter(sa -> Objects.equals(sa.getId(), dimensionValueId))
                    .findFirst().orElse(null);
            String newAreaName = newArea == null ? "" : newArea.getName();
            // 区域
            for (OrgBasicDto model : orgList) {
                Organization old = organizationMapper.selectByPrimaryKey(model.getId());
                if (old == null) {
                    throw new ApplicationException(CommonConstants.JSONNULLOBJECT);
                }
                Organization copy = CommonUtils.copyProperties(old, new Organization());
                if (!dimensionValueId.equalsIgnoreCase(old.getAreaId())) {
                    old.setAreaId(dimensionValueId);
                    NameDto oldArea = areaNameDtoList.stream()
                            .filter(sa -> Objects.equals(sa.getId(), copy.getAreaId())).findFirst().orElse(null);
                    String oldAreaName = oldArea == null ? "" : oldArea.getName();
                    UpdateLogParams updateLogParams = new UpdateLogParams();
                    updateLogParams.setOperateLogType(OperateLogType.OperationLogOrganization.value());
                    updateLogParams.setComment("");
                    updateLogParams.setOperationModule(OperationModule.Organization.value());
                    updateLogParams.setOperationContent(OrganizationMessage.AreaLogMessage);
                    updateLogParams.setOriginalState(oldAreaName);
                    updateLogParams.setUpdateState(newAreaName);
                    updateLogParams.setOperationObject(copy.getName());
                    updateLogParams.setOperationAction(OperationAction.Update.value());
                    logList.add(updateLogParams);
                    logger.debug("Start to update Organization [ {} ]", old.getId());
                    organizationMapper.updateByPrimaryKey(old);
                }
            }
            operationLogService.addOrDeleteDataAddLog(logList);
        } else {
            // 自定义的时候,更新DimensionValurOrg Table
            List<DimensionValueOrgDto> orgDtoList = new ArrayList<>();
            for (OrgBasicDto model : orgList) {
                DimensionValueOrgExample dimensionValueOrgExample = new DimensionValueOrgExample();
                dimensionValueOrgExample.createCriteria().andDimensionValueIdEqualTo(dimensionValueId)
                        .andOrganizationIdEqualTo(model.getId());
                List<DimensionValueOrg> query = dimensionValueOrgMapper.selectByExample(dimensionValueOrgExample);
                if ((query == null || query.isEmpty())
                        && orgDtoList.stream().noneMatch(s -> Objects.equals(s.getOrganizationId(), model.getId())
                        && Objects.equals(s.getDimensionValueId(), dimensionValueId))) {
                    DimensionValueOrgDto dto = new DimensionValueOrgDto();
                    dto.setId(CommonUtils.getUUID());
                    dto.setDimensionValueId(dimensionValueId);
                    dto.setOrganizationId(model.getId());
                    orgDtoList.add(dto);
                }
                UpdateLogParams updateLogParams = new UpdateLogParams();
                updateLogParams.setOperateLogType(OperateLogType.OperationLogOrganization.value());
                updateLogParams.setComment("");
                updateLogParams.setOperationModule(OperationModule.BasicDataDimensionValue.value());
                updateLogParams.setOperationContent(dimensionName);
                updateLogParams.setOriginalState("");
                updateLogParams.setUpdateState("");
                updateLogParams.setOperationObject(model.getName());
                updateLogParams.setOperationAction(OperationAction.New.value());
                operationLogService.addOrDeleteDataAddLog(updateLogParams);
            }
            // 添加新数据
            List<DimensionValueOrg> attr = orgDtoList.stream()
                    .map(s -> CommonUtils.copyProperties(s, new DimensionValueOrg())).collect(Collectors.toList());
            for (DimensionValueOrg oneAttr : attr) {
                logger.debug("Start to insert DimensionValueOrg [ {} ]", oneAttr.getId());
                dimensionValueOrgMapper.insert(oneAttr);
            }
        }
        OperationResultDto operationResultDto = new OperationResultDto();
        operationResultDto.setResult(true);
        return operationResultDto;
    }

    @SuppressWarnings("rawtypes")
    private OperationResultDto checkOrgNameOrOrgCode(OrganizationDto orgDto) {
        OrganizationExample example = new OrganizationExample();
        if (orgDto.getId() == null) {
            example.or().andClientCodeEqualTo(orgDto.getClientCode()).andNameEqualTo(orgDto.getName());
            example.or().andClientCodeEqualTo(orgDto.getClientCode()).andCodeEqualTo(orgDto.getCode());
        } else {
            example.or().andClientCodeEqualTo(orgDto.getClientCode()).andIdNotEqualTo(orgDto.getId())
                    .andNameEqualTo(orgDto.getName());
            example.or().andClientCodeEqualTo(orgDto.getClientCode()).andIdNotEqualTo(orgDto.getId())
                    .andCodeEqualTo(orgDto.getCode());
        }
        Organization query = organizationMapper.selectByExample(example).stream().findFirst().orElse(null);
        if (query != null) {
            return new OperationResultDto(false, OrganizationMessage.OrgNameOrCodeIsExiste);
        }
        return new OperationResultDto(true);
    }

    /**
     * update a org info
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public OperationResultDto<Object> updateOrg(OrganizationDto orgDto) {
        try {
            Assert.notNull(orgDto, "orgDto Null Exception on updateOrg");
            if (orgDto.getEnterpriseAccountSetOrgList() == null) {
                orgDto.setEnterpriseAccountSetOrgList(new ArrayList<>());
            }

            OperationResultDto result = checkOrgNameOrOrgCode(orgDto);
            if (result != null && result.getResult()) {
                result = this.checkCodeTaxPaymentNo(orgDto);
            }
            if (result != null && !BooleanUtils.isTrue(result.getResult())) {
                return new OperationResultDto(result.getResult(), result.getResultMsg());
            }
            Organization org = orgDto.getId() != null ? organizationMapper.selectByPrimaryKey(orgDto.getId()) : null;
            if (org == null) {
                return new OperationResultDto(false, OrganizationMessage.NotFindOrg);
            }

            // code唯一验证
            OrganizationValidateDto orgValidateDto1 = new OrganizationValidateDto();
            orgValidateDto1.setId(org.getId());
            orgValidateDto1.setValue(orgDto.getCode());
            if (!codeUniqueValidate(orgValidateDto1)) {
                return new OperationResultDto(false, OrganizationMessage.OrgNameOrCodeIsExiste);
            }

            // 纳税人识别号唯一性验证
            OrganizationValidateDto orgValidateDto2 = new OrganizationValidateDto();
            orgValidateDto2.setId(org.getId());
            orgValidateDto2.setValue(orgDto.getTaxPayerNumber());
            if (!taxPayerNumberUniqueValidate(orgValidateDto2)) {
                return new OperationResultDto(false, OrganizationMessage.OrgNameOrCodeIsExiste);
            }
            Organization orgOriginal = new Organization();
            orgOriginal = CommonUtils.copyProperties(org, orgOriginal);
            orgOriginal.setpLevel(orgOriginal.getpLevel());
            // 上级机构验证
            if (Strings.isBlank(orgDto.getParentId())
                    || Strings.equals(orgDto.getParentId(), OrganizationConstant.NoParentId)) {
                orgDto.setParentId(null);
                org.setpLevel(0);
            } else {
                // 机构添加层级
                Organization query = organizationMapper.selectByPrimaryKey(orgDto.getParentId());
                if (query != null) {
                    org.setpLevel(query.getpLevel() + 1);
                }
            }

            if (!Strings.equals(orgDto.getParentId(), org.getParentId())) {
                // 如果修改了上级机构
                OperationResultDto<Object> checkParentIdRet = checkParentId(orgDto);
                if (checkParentIdRet != null && !checkParentIdRet.getResult()) {
                    return checkParentIdRet;
                }
            }
            org.setName(orgDto.getName());
            org.setTaxPayerNumber(orgDto.getTaxPayerNumber());
            org.setParentId(orgDto.getParentId());
            org.setStructureId(orgDto.getStructureId());
            org.setRegionId(orgDto.getRegionId());
            org.setAreaId(orgDto.getAreaId());
            org.setUpdateTime(new Date());
            org.setIndustryId(orgDto.getIndustryId());
            org.setBusinessUnitId(orgDto.getBusinessUnitId());
            Organization orgUpdate = org;

            organizationMapper.updateByPrimaryKey(org);

            OperationResultDto<Object> validatesetRet = validateEnterpriseAccountSetDateTimeOverlap(
                    orgDto.getEnterpriseAccountSetOrgList());
            if (!validatesetRet.getResult()) {
                return validatesetRet;
            }

            // 更新机构账套
            EnterpriseAccountSetOrgExample example = new EnterpriseAccountSetOrgExample();
            pwc.taxtech.atms.entity.EnterpriseAccountSetOrgExample.Criteria criteria = example.createCriteria();
            if (orgDto.getId() != null) {
                criteria.andOrganizationIdEqualTo(orgDto.getId());
            } else {
                criteria.andOrganizationIdIsNull();
            }
            List<EnterpriseAccountSetOrg> enterpriseAccountSetOrgList = enterpriseAccountSetOrgMapper
                    .selectByExample(example);
            for (EnterpriseAccountSetOrgDto p : orgDto.getEnterpriseAccountSetOrgList()) {
                p.setEffectiveDate(Strings.isBlank(p.getEffectiveDateStr()) ? p.getEffectiveDate()
                        : DateTimeFormat.forPattern("yyyy-MM-dd").parseDateTime(p.getEffectiveDateStr() + "-01")
                        .toDate());
                p.setExpiredDate(Strings.isBlank(p.getExpiredDateStr()) ? p.getExpiredDate()
                        : DateTimeFormat.forPattern("yyyy-MM-dd").parseDateTime(p.getExpiredDateStr() + "-01")
                        .plusMonths(1).minusDays(1).toDate());
                if (enterpriseAccountSetOrgList != null
                        && enterpriseAccountSetOrgList.stream().anyMatch(t -> Strings.equals(t.getId(), p.getId()))) {
                    EnterpriseAccountSetOrg tempDto = enterpriseAccountSetOrgList.stream()
                            .filter(t -> Strings.equals(t.getId(), p.getId())).findFirst().orElse(null);
                    Assert.notNull(tempDto, "tempDto null exception on updateOrg");
                    tempDto.setEffectiveDate(p.getEffectiveDate());
                    tempDto.setEnterpriseAccountSetId(p.getEnterpriseAccountSetId());
                    tempDto.setExpiredDate(p.getExpiredDate());
                    enterpriseAccountSetOrgMapper.updateByPrimaryKey(tempDto);
                } else {
                    EnterpriseAccountSetOrg temp = new EnterpriseAccountSetOrg();
                    temp.setId(CommonUtils.getUUID());
                    temp.setEnterpriseAccountSetId(p.getEnterpriseAccountSetId());
                    temp.setOrganizationId(p.getOrganizationId());
                    temp.setEffectiveDate(p.getEffectiveDate());
                    temp.setExpiredDate(p.getExpiredDate());
                    enterpriseAccountSetOrgMapper.insert(temp);
                }
            }

            List<EnterpriseAccountSetOrg> deleteSetList = enterpriseAccountSetOrgList.stream().filter(p -> orgDto
                    .getEnterpriseAccountSetOrgList().stream().noneMatch(sa -> Strings.equals(sa.getId(), p.getId())))
                    .collect(Collectors.toList());

            if (deleteSetList != null && !deleteSetList.isEmpty()) {
                deleteSetList.stream()
                        .forEach(delSet -> enterpriseAccountSetOrgMapper.deleteByPrimaryKey(delSet.getId()));
            }

            OrganizationServiceTemplateGroupExample oSTGExample = new OrganizationServiceTemplateGroupExample();
            pwc.taxtech.atms.entity.OrganizationServiceTemplateGroupExample.Criteria oSTGCriteria = oSTGExample
                    .createCriteria();
            if (orgDto.getId() != null) {
                oSTGCriteria.andOrganizationIdEqualTo(orgDto.getId());
            } else {
                oSTGCriteria.andOrganizationIdIsNull();
            }
            List<OrganizationServiceTemplateGroup> currentOrganizationServiceTemplateGroupList = organizationServiceTemplateGroupMapper
                    .selectByExample(oSTGExample);

            List<OrganizationServiceTemplateGroup> updateOrganizationServiceTemplateGroupList = new ArrayList<>();
            TaxPayerReportRuleExample taxExample = new TaxPayerReportRuleExample();
            taxExample.or().andIsDefaultEqualTo(true);
            Assert.notNull(orgDto.getId(), "orgDto id null exception on updateOrg");
            String sqlValue = "%" + orgDto.getId() + "%";
            taxExample.or().andOrganizationIdLike(sqlValue);
            List<TaxPayerReportRule> reportRules = taxPayerReportRuleMapper.selectByExample(taxExample);
            TaxPayerReportRule activeRule = reportRules.stream()
                    .filter(t -> t.getOrganizationId() == null ? false : t.getOrganizationId().contains(orgDto.getId()))
                    .findFirst().orElse(null);
            // C#中在此处定义的defaultRule在下文中未被引用,JAVA中将其删除

            // 更新机构服务
            currentOrganizationServiceTemplateGroupList.stream()
                    .forEach(tg -> organizationServiceTemplateGroupMapper.deleteByPrimaryKey(tg.getId()));

            // For VAT, update Rule Engine tables instead of
            OrganizationServiceTemplateGroupDto vatSetting = orgDto.getOrganizationServiceTemplateGroupList().stream()
                    .filter(t -> Strings.equals(t.getServiceTypeId(), ServiceTypeEnum.VAT.value().toString()))
                    .findFirst().orElse(null);
            if (vatSetting != null) {
                TemplateGroup templateGrp = vatSetting.getTemplateGroupId() != null
                        ? templateGroupMapper.selectByPrimaryKey(vatSetting.getTemplateGroupId())
                        : null;
                // In organization module tax payer type is 1&2 while 0&1 in rule engine
                int newTaxPayerType = (templateGrp != null && templateGrp.getPayTaxType() != null)
                        ? (templateGrp.getPayTaxType() - 1)
                        : (VatTaxPayerTypeEnum.General.value());
                if ((activeRule != null)
                        && (Long.compare(activeRule.getTemplateGroupId(), vatSetting.getTemplateGroupId()) != 0)) {
                    // Multiple organizations in 1 rule
                    if (!Strings.equals(activeRule.getOrganizationId(), orgDto.getId())) {
                        activeRule.setOrganizationId(
                                activeRule.getOrganizationId().replace(orgDto.getId(), "").replace(",,", ","));
                        Date now = new Date();
                        TaxPayerReportRule newRule = new TaxPayerReportRule();
                        newRule.setId(distributedIdService.nextId());
                        newRule.setIsDefault(false);
                        newRule.setOrganizationId(orgDto.getId());
                        newRule.setTemplateGroupId(vatSetting.getTemplateGroupId());
                        newRule.setTaxPayerType(newTaxPayerType); // Use tax payer type related to template group
                        newRule.setCreateTime(now);
                        newRule.setUpdateTime(now);
                        taxPayerReportRuleMapper.insertSelective(newRule);
                    } else {
                        activeRule.setTemplateGroupId(vatSetting.getTemplateGroupId());
                        activeRule.setTaxPayerType(newTaxPayerType);
                    }
                } else { // If currently no rule and new rule should be added
                    Date now = new Date();
                    TaxPayerReportRule newRule = new TaxPayerReportRule();
                    newRule.setId(distributedIdService.nextId());
                    newRule.setIsDefault(false);
                    newRule.setOrganizationId(orgDto.getId());
                    newRule.setTemplateGroupId(vatSetting.getTemplateGroupId());
                    newRule.setTaxPayerType(newTaxPayerType); // Use tax payer type related to template group
                    newRule.setCreateTime(now);
                    newRule.setUpdateTime(now);
                    taxPayerReportRuleMapper.insertSelective(newRule);
                }
            } else if (activeRule != null) { // If no setting, remove non-default rule
                taxPayerReportRuleMapper.deleteByPrimaryKey(activeRule.getId());
            }
            for (OrganizationServiceTemplateGroupDto p : orgDto.getOrganizationServiceTemplateGroupList()) {
                OrganizationServiceTemplateGroup temp = new OrganizationServiceTemplateGroup();
                temp.setId(distributedIdService.nextId());
                temp.setOrganizationId(orgDto.getId());
                temp.setServiceTypeId(p.getServiceTypeId());
                temp.setTemplateGroupId(p.getTemplateGroupId());
                updateOrganizationServiceTemplateGroupList.add(temp);
                organizationServiceTemplateGroupMapper.insertSelective(temp);
            }

            // 更新自定义属性
            // C#中的内部类CommonLogParams 在JAVA中替换成UpdateLogParams中
            List<UpdateLogParams> selfDimensionList;
            selfDimensionList = updateSelfDimensionList(orgDto);

            UpdateLogParams updateLogParams = new UpdateLogParams();
            updateLogParams.setOriginalState(orgOriginal);
            updateLogParams.setUpdateState(orgUpdate);
            updateLogParams.setOperationModule(Organization.value());
            updateLogParams.setOperateLogType(OperationLogOrganization.value());
            updateLogParams.setOperationContent(orgUpdate.getName());
            updateLogParams.setOperationObject(org.getName());
            updateLogParams.setOperationAction(OperationAction.Update.value());
            updateLogParams.setComment("");
            operationLogService.updateDataAddLog(updateLogParams);

            updateEnterpriseAccountSetOrgLog(org.getName(), enterpriseAccountSetOrgList,
                    orgDto.getEnterpriseAccountSetOrgList());
            updateOrganizationServiceTemplateGroupLog(org.getName(), currentOrganizationServiceTemplateGroupList,
                    updateOrganizationServiceTemplateGroupList);
            operationLogService.addOrDeleteDataAddLog(selfDimensionList);
            return new OperationResultDto(true);
        } catch (Exception ex) {
            logger.error("UpdateOrg出错了:" + ex, ex);
            logger.error("标记回滚, ready to call setRollbackOnly");
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new OperationResultDto(false, ex.getMessage());
        }
    }

    private void updateOrganizationServiceTemplateGroupLog(String operateObject,
                                                           List<OrganizationServiceTemplateGroup> currentList, List<OrganizationServiceTemplateGroup> updateList) {
        currentList = currentList == null ? new ArrayList<>() : currentList;
        updateList = updateList == null ? new ArrayList<>() : updateList;
        // 新增
        List<OrganizationServiceTemplateGroup> tempCurrentList = currentList;
        List<OrganizationServiceTemplateGroup> addList = updateList.stream()
                .filter(p -> !tempCurrentList.stream()
                        .anyMatch(sa -> Strings.equals(sa.getServiceTypeId(), p.getServiceTypeId())))
                .collect(Collectors.toList());

        // 删除
        List<OrganizationServiceTemplateGroup> tempUpdateList = updateList;
        List<OrganizationServiceTemplateGroup> deleteList = currentList.stream()
                .filter(p -> !tempUpdateList.stream()
                        .anyMatch(sa -> Strings.equals(sa.getServiceTypeId(), p.getServiceTypeId())))
                .collect(Collectors.toList());

        // 修改
        List<OrganizationServiceTemplateGroup> updates = updateList.stream()
                .filter(p -> tempCurrentList.stream()
                        .anyMatch(sa -> Strings.equals(sa.getServiceTypeId(), p.getServiceTypeId())
                                && (Long.compare(sa.getTemplateGroupId(), p.getTemplateGroupId()) != 0)))
                .collect(Collectors.toList());

        List<UpdateLogParams> addLogList = new ArrayList<>();

        List<TemplateGroup> queryTemplate = templateGroupMapper.selectByExample(null);
        List<ServiceType> queryService = serviceTypeMapper.selectByExample(null);

        for (OrganizationServiceTemplateGroup item : addList) {
            ServiceType st1 = queryService.stream().filter(sa -> Strings.equals(sa.getId(), item.getServiceTypeId()))
                    .findFirst().orElse(null);
            Assert.notNull(st1, "queryService result null exception in updateOrganizationServiceTemplateGroupLog");
            TemplateGroup st2 = queryTemplate.stream()
                    .filter(sa -> Long.compare(sa.getId(), item.getTemplateGroupId()) == 0).findFirst().orElse(null);
            Assert.notNull(st2, "queryTemplate result null exception in updateOrganizationServiceTemplateGroupLog");
            String updateStr = st1.getName() + CommonConstants.OneSpace + st2.getName();
            UpdateLogParams updateLogParams = new UpdateLogParams();
            updateLogParams.setUpdateState(updateStr);
            updateLogParams.setOriginalState("");
            updateLogParams.setOperationContent(OrganizationMessage.OrganizationServiceTemplateGroup);
            updateLogParams.setOperationObject(operateObject);
            updateLogParams.setOperationModule(OperationModule.Organization.value());
            updateLogParams.setOperateLogType(OperateLogType.OperationLogOrganization.value());
            updateLogParams.setComment("");
            updateLogParams.setOperationAction(OperationAction.New.value());
            addLogList.add(updateLogParams);
        }

        //todo: just for test at here, remove comment later
//        for (OrganizationServiceTemplateGroup item : deleteList) {
//            ServiceType st1 = queryService.stream().filter(sa -> Strings.equals(sa.getId(), item.getServiceTypeId()))
//                    .findFirst().orElse(null);
//            Assert.notNull(st1, "queryService result null exception on updateOrganizationServiceTemplateGroupLog");
//            TemplateGroup st2 = queryTemplate.stream()
//                    .filter(sa -> Long.compare(sa.getId(), item.getTemplateGroupId())==0).findFirst().orElse(null);
//            Assert.notNull(st2, "queryTemplate result null exception on updateOrganizationServiceTemplateGroupLog");
//            String updateStr = st1.getName() + CommonConstants.OneSpace + st2.getName();
//            UpdateLogParams updateLogParams = new UpdateLogParams();
//            updateLogParams.setUpdateState("");
//            updateLogParams.setOriginalState(updateStr);
//            updateLogParams.setOperationContent(OrganizationMessage.OrganizationServiceTemplateGroup);
//            updateLogParams.setOperationObject(operateObject);
//            updateLogParams.setOperationModule(OperationModule.Organization.value());
//            updateLogParams.setOperateLogType(OperateLogType.OperationLogOrganization.value());
//            updateLogParams.setComment("");
//            updateLogParams.setOperationAction(OperationAction.Delete.value());
//            addLogList.add(updateLogParams);
//        }

//        for (OrganizationServiceTemplateGroup item : updates) {
//            OrganizationServiceTemplateGroup current = currentList.stream()
//                    .filter(sa -> Strings.equals(sa.getServiceTypeId(), item.getServiceTypeId())).findFirst()
//                    .orElse(null);
//            if (current != null) {
//                ServiceType tService = queryService.stream()
//                        .filter(sa -> Strings.equals(sa.getId(), item.getServiceTypeId())).findFirst().orElse(null);
//                Assert.notNull(tService, "tService null exception in updateOrganizationServiceTemplateGroupLog");
//                String serviceName = tService.getName();
//
//                TemplateGroup updateTemplate = queryTemplate.stream()
//                        .filter(sa -> Long.compare(sa.getId(), item.getTemplateGroupId())==0).findFirst().orElse(null);
//                Assert.notNull(updateTemplate,
//                        "updateTemplate null exception in updateOrganizationServiceTemplateGroupLog");
//                String updateStr = updateTemplate.getName();
//
//                TemplateGroup currentTemplate = queryTemplate.stream()
//                        .filter(sa -> Long.compare(sa.getId(), current.getTemplateGroupId())==0).findFirst()
//                        .orElse(null);
//                Assert.notNull(currentTemplate,
//                        "currentTemplate null exception in updateOrganizationServiceTemplateGroupLog");
//                String currentStr = currentTemplate.getName();
//
//                UpdateLogParams updateLogParams = new UpdateLogParams();
//                updateLogParams.setUpdateState(updateStr);
//                updateLogParams.setOriginalState(currentStr);
//                updateLogParams.setOperationContent(OrganizationMessage.OrganizationServiceTemplateGroup);
//                updateLogParams.setOperationObject(operateObject + DashSignSeparator + serviceName);
//                updateLogParams.setOperationModule(OperationModule.Organization.value());
//                updateLogParams.setOperateLogType(OperateLogType.OperationLogOrganization.value());
//                updateLogParams.setComment("");
//                updateLogParams.setOperationAction(OperationAction.Update.value());
//                addLogList.add(updateLogParams);
//            }
//
//        }
        operationLogService.addOrDeleteDataAddLog(addLogList);
    }

    private void updateEnterpriseAccountSetOrgLog(String operateObject, List<EnterpriseAccountSetOrg> currentList,
                                                  List<EnterpriseAccountSetOrgDto> updateList) {
        List<String> fromList = new ArrayList<>();
        List<String> toList = new ArrayList<>();
        List<EnterpriseAccountSet> set = enterpriseAccountSetMapper.selectByExample(null);
        if (currentList != null && !currentList.isEmpty()) {
            fromList = set.stream()
                    .filter(q -> currentList.stream()
                            .anyMatch(p -> Strings.equals(p.getEnterpriseAccountSetId(), q.getId())))
                    .sorted(comparing(EnterpriseAccountSet::getId, nullsFirst(naturalOrder())))
                    .map(EnterpriseAccountSet::getName).collect(Collectors.toList());
        }
        if (updateList != null && !updateList.isEmpty()) {
            toList = set.stream()
                    .filter(q -> updateList.stream()
                            .anyMatch(p -> Strings.equals(p.getEnterpriseAccountSetId(), q.getId())))
                    .sorted(comparing(EnterpriseAccountSet::getId, nullsFirst(naturalOrder())))
                    .map(EnterpriseAccountSet::getName).collect(Collectors.toList());
        }
        String from = String.join(Comma, fromList);
        String to = String.join(Comma, toList);

        if (!Strings.equals(from, to)) {
            UpdateLogParams log = new UpdateLogParams();
            log.setOperationAction(OperationAction.Update.value());
            log.setComment("");
            log.setOperateLogType(OperateLogType.OperationLogOrganization.value());
            log.setOperationModule(OperationModule.Organization.value());
            log.setOperationObject(operateObject);
            log.setOperationContent(OrganizationMessage.RelevantEnterpriseAccountSet);
            log.setOriginalState(from);
            log.setUpdateState(to);
            operationLogService.addOrDeleteDataAddLog(log);
        }
    }

    /**
     * 修改自定义纬度的值
     */
    private List<UpdateLogParams> updateSelfDimensionList(OrganizationDto orgDto) {
        Assert.notNull(orgDto, "orgDto null exception in updateSelfDimensionList");
        List<UpdateLogParams> logList = new ArrayList<>();
        DimensionExample example1 = new DimensionExample();
        example1.createCriteria().andIsActiveEqualTo(true);
        List<Dimension> dimensionList = dimensionMapper.selectByExample(example1);

        DimensionValueExample example2 = new DimensionValueExample();
        example2.createCriteria().andIsActiveEqualTo(true);
        List<DimensionValue> dimensionValueList = dimensionValueMapper.selectByExample(example2);

        DimensionValueOrgExample example3 = new DimensionValueOrgExample();
        example3.createCriteria().andOrganizationIdEqualTo(orgDto.getId());
        List<DimensionValueOrg> oldDimensionOrgList = dimensionValueOrgMapper.selectByExample(example3);
        List<DimensionValueOrgDto> newDimensionOrgList = orgDto.getDimensionValueOrgList();

        if (newDimensionOrgList == null) {
            newDimensionOrgList = new ArrayList<>();
        }

        if (oldDimensionOrgList.isEmpty() && newDimensionOrgList.isEmpty()) {
            return logList;
        }
        List<DimensionValueJoinDimensionDto> queryInfo = dimensionValueMapper.selectDimensionValueJoinDimension();

        List<DimensionValueOrg> updateDimensionOrgList = new ArrayList<>();
        List<DimensionValueOrg> addDimensionOrgList = new ArrayList<>();
        List<DimensionValueOrg> deleteDimensionOrgList = new ArrayList<>();

        for (Dimension dimension : dimensionList) {
            List<String> valueList = dimensionValueList.stream()
                    .filter(p -> Strings.equals(p.getDimensionId(), dimension.getId()))
                    .map(p -> p.getId().toLowerCase()).collect(Collectors.toList());

            DimensionValueOrg old = oldDimensionOrgList.stream()
                    .filter(p -> valueList.contains(p.getDimensionValueId().toLowerCase())).findFirst().orElse(null);

            DimensionValueOrgDto newObj = newDimensionOrgList.stream()
                    .filter(p -> valueList.contains(p.getDimensionValueId().toLowerCase())).findFirst().orElse(null);

            // 都没有值
            if (old == null && newObj == null) {
                continue;
            }

            // 两个都有值
            if (old != null && newObj != null) {
                old.setDimensionValueId(newObj.getDimensionId());
                updateDimensionOrgList.add(old);

                DimensionValueJoinDimensionDto info = queryInfo.stream()
                        .filter(sa -> Strings.equals(sa.getDimensionValueId(), old.getDimensionValueId())).findFirst()
                        .orElse(null);
                DimensionValueJoinDimensionDto newInfo = queryInfo.stream()
                        .filter(sa -> Strings.equals(sa.getDimensionValueId(), newObj.getDimensionValueId()))
                        .findFirst().orElse(null);
                // 修改
                UpdateLogParams updateLogParams = new UpdateLogParams();
                updateLogParams.setOperationAction(OperationAction.Update.value());
                updateLogParams.setComment("");
                updateLogParams.setOperateLogType(OperationLogOrganization.value());
                updateLogParams.setOperationModule(Organization.value());
                updateLogParams.setOperationObject(orgDto.getName());
                updateLogParams.setOperationContent(info == null ? "" : info.getDimensionName());
                updateLogParams.setOriginalState(info == null ? "" : info.getDimensionValue());
                updateLogParams.setUpdateState(newInfo == null ? "" : newInfo.getDimensionValue());
                logList.add(updateLogParams);
            }

            if (old != null && newObj == null) {
                // 需要删除
                deleteDimensionOrgList.add(old);
                DimensionValueJoinDimensionDto info = queryInfo.stream()
                        .filter(sa -> Strings.equals(sa.getDimensionValueId(), old.getDimensionValueId())).findFirst()
                        .orElse(null);

                UpdateLogParams updateLogParams = new UpdateLogParams();
                updateLogParams.setOperationAction(OperationAction.Update.value());
                updateLogParams.setComment("");
                updateLogParams.setOperateLogType(OperationLogOrganization.value());
                updateLogParams.setOperationModule(Organization.value());
                updateLogParams.setOperationObject(orgDto.getName());
                updateLogParams.setOperationContent(info == null ? "" : info.getDimensionName());
                updateLogParams.setOriginalState(info == null ? "" : info.getDimensionValue());
                updateLogParams.setUpdateState("");
                logList.add(updateLogParams);
            }

            if (old == null && newObj != null) {
                // 需要添加
                DimensionValueOrg dimensionValueOrg = new DimensionValueOrg();
                dimensionValueOrg.setDimensionValueId(newObj.getDimensionValueId());
                dimensionValueOrg.setOrganizationId(orgDto.getId());
                dimensionValueOrg.setId(CommonUtils.getUUID());
                addDimensionOrgList.add(dimensionValueOrg);

                DimensionValueJoinDimensionDto info = queryInfo.stream()
                        .filter(sa -> Strings.equals(sa.getDimensionValueId(), newObj.getDimensionValueId()))
                        .findFirst().orElse(null);
                UpdateLogParams updateLogParams = new UpdateLogParams();
                updateLogParams.setOperationAction(OperationAction.Update.value());
                updateLogParams.setComment("");
                updateLogParams.setOperateLogType(OperationLogOrganization.value());
                updateLogParams.setOperationModule(Organization.value());
                updateLogParams.setOperationObject(orgDto.getName());
                updateLogParams.setOperationContent(info == null ? "" : info.getDimensionName());
                updateLogParams.setOriginalState("");
                updateLogParams.setUpdateState(info == null ? "" : info.getDimensionValue());
                logList.add(updateLogParams);
            }
        }
        if (!addDimensionOrgList.isEmpty()) {
            addDimensionOrgList.stream().forEach(d -> dimensionValueOrgMapper.insert(d));
        }

        if (!updateDimensionOrgList.isEmpty()) {
            updateDimensionOrgList.stream().forEach(d -> dimensionValueOrgMapper.updateByPrimaryKey(d));
        }

        if (!deleteDimensionOrgList.isEmpty()) {
            deleteDimensionOrgList.stream().forEach(d -> dimensionValueOrgMapper.deleteByPrimaryKey(d.getId()));
        }
        return logList;
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    private OperationResultDto<Object> checkParentId(OrganizationDto orgDto) {
        if (Strings.equals(orgDto.getParentId(), orgDto.getId())) {
            return new OperationResultDto(false, OrganizationMessage.ParentIdCannotEqualsId);
        }

        OrganizationExample example = new OrganizationExample();
        example.createCriteria().andIsActiveEqualTo(true);
        List<Organization> orgList = organizationMapper.selectByExample(example);
        List<Organization> subList = this.getSubOrganization(orgDto.getId(), orgList);
        Assert.notNull(subList, "subList null exception in checkParentId");
        if (subList.stream().anyMatch(sa -> Strings.equals(sa.getId(), sa.getParentId()))) {
            return new OperationResultDto(false, OrganizationMessage.ParentIdCannotBeSubId);
        }
        return new OperationResultDto(true);
    }

    /**
     * 获取所有子机构
     */
    private List<Organization> getSubOrganization(String orgid, List<Organization> orglist) {
        List<Organization> retList = new ArrayList<>();
        List<Organization> subList = orglist.stream().filter(sa -> Strings.equals(sa.getParentId(), orgid))
                .collect(Collectors.toList());

        if (!subList.isEmpty()) {
            subList.stream().forEach(s -> retList.add(s));
        }

        for (Organization item : subList) {
            List<Organization> tempList = getSubOrganization(item.getId(), orglist);
            if (!tempList.isEmpty()) {
                tempList.stream().forEach(t -> retList.add(t));
            }
        }
        return retList;
    }

    public OrgGeneralInfoDto getGeneralInfo(String orgId) {
        return getOrgGeneralInfo(orgId);
    }

    public List<DevTreeDto> getOrgIvhTreeList(Integer useType, String orgSetId) {
        //todo
        List<DevTreeDto> result = Lists.newArrayList();
        List<IvhTreeDto> orgDtoList = Lists.newArrayList();
        List<Organization> orgList;
        OrganizationExample orgExample = new OrganizationExample();

        if (useType < 2) {
            orgList = organizationMapper.selectByExample(orgExample);
        } else {
            EnterpriseAccountSetOrgExample tmpExample = new EnterpriseAccountSetOrgExample();
            EnterpriseAccountSetOrgExample.Criteria criteria = tmpExample.createCriteria();
            criteria.andEnterpriseAccountSetIdEqualTo(orgSetId);
            List<EnterpriseAccountSetOrg> enAccountSetOrgList = enterpriseAccountSetOrgMapper.selectByExample(tmpExample);
            if (CollectionUtils.isNotEmpty(enAccountSetOrgList)) {
                List<String> orgIdList = enAccountSetOrgList.stream().map(EnterpriseAccountSetOrg::getOrganizationId)
                        .collect(toList());
                OrganizationExample.Criteria orgCriteria = orgExample.createCriteria();
                orgCriteria.andIdIn(orgIdList);
                orgList = organizationMapper.selectByExample(orgExample);
            } else {
                orgList = Lists.newArrayList();
            }
        }
        if (CollectionUtils.isNotEmpty(orgList)) {
            //find rootOrg
            List<Organization> rootOrgList;
            if (useType == 1) {
                rootOrgList = orgList.stream().filter(x -> StringUtils.isBlank(x.getParentId())).collect(toList());
            } else {
                rootOrgList = orgList.stream().filter(x -> StringUtils.isBlank(x.getParentId()) && x.getIsActive())
                        .collect(toList());
            }
            List<ServiceType> serviceList = Lists.newArrayList();

            for (Organization org : rootOrgList) {
                IvhTreeDto root = new IvhTreeDto();
                root.setChildren(Lists.newArrayList());
                root.setLabel(org.getName());
                root.setValue(org);
                orgDtoList.add(generateIvhTreeDto(org, orgList, serviceList, useType));
            }

        }
        return orgDtoList.stream().map(this::devTreeDtoMapper).collect(toList());
    }

    private DevTreeDto devTreeDtoMapper(IvhTreeDto ivhTreeDto) {
        DevTreeDto dto = new DevTreeDto();
        dto.setText(ivhTreeDto.getLabel());
        List<IvhTreeDto> childList = ivhTreeDto.getChildren();
        if (CollectionUtils.isNotEmpty(childList)) {
            dto.setItems(Lists.newArrayList());
            for (IvhTreeDto ivh : childList) {
                dto.getItems().add(devTreeDtoMapper(ivh));
            }
        }
        dto.setId(ivhTreeDto.getId());
        dto.setData(ivhTreeDto);
        return dto;
    }

    private IvhTreeDto generateIvhTreeDto(Organization parentOrg, List<Organization> orgList,
                                          List<ServiceType> serviceList, int useType) {
        IvhTreeDto result = new IvhTreeDto();
        OrganizationDto parentOrgDto = new OrganizationDto();
        CommonUtils.copyProperties(parentOrg, parentOrgDto);
        if (null != parentOrg && StringUtils.isNotBlank(parentOrg.getId())) {
            parentOrgDto.setParentName(orgList.stream().filter(x -> StringUtils.equals(x.getId(), parentOrg.getParentId()))
                    .findFirst().map(x -> x.getName()).orElse(StringUtils.EMPTY));
        }

        List<Organization> subOrgList;
        if (useType == 1) {
            subOrgList = orgList.stream().filter(x -> StringUtils.equals(x.getParentId(), parentOrg.getId())).collect(toList());
        } else {
            subOrgList = orgList.stream().filter(x -> StringUtils.equals(x.getParentId(), parentOrg.getId()) && x.getIsActive())
                    .collect(toList());
        }
        parentOrgDto.setSubOrgs(Lists.newArrayList());
        List<IvhTreeDto> children = Lists.newArrayList();

        //create and add subtrees to the current node
        for (Organization subOrg : subOrgList) {
            children.add(generateIvhTreeDto(subOrg, orgList, serviceList, useType));
        }
        result.setId(parentOrg.getId());
        result.setLabel(parentOrgDto.getName());
        result.setValue(parentOrgDto);
        result.setChildren(children);

        return result;
    }

    private OrgGeneralInfoDto getOrgGeneralInfo(String orgId) {
        List<OrgGeneralInfoMiddleDto> query = organizationMapper.selectJoinToOrgGeneralInfo();
        List<OrgGeneralInfoMiddleDto> filter = query.stream().filter(x -> Strings.equals(x.getId(), orgId))
                .collect(Collectors.toList());
        if (filter.isEmpty()) {
            return null;
        }

        List<String> serviceList = filter.stream().map(OrgGeneralInfoMiddleDto::getServiceName).distinct()
                .collect(Collectors.toList());
        List<String> accountSetList = filter.stream().map(OrgGeneralInfoMiddleDto::getAccountSetName).distinct()
                .collect(Collectors.toList());
        OrgGeneralInfoMiddleDto row = filter.get(0);

        String areaName = "";
        String businessUnitName = "";

        if (row.getAreaName() == null) {
            areaName = getAreaNameById(row.getAreaId());
        }

        if (row.getBusinessUnitName() == null) {
            businessUnitName = getBusinessUnitNameById(row.getBusinessUnitId());
        }
        OrgGeneralInfoDto ret = new OrgGeneralInfoDto();
        ret.setOrgName(row.getOrgName());
        ret.setTaxPayerNumber(row.getTaxPayerNumber());
        ret.setAccountSetName(
                String.join(",", (accountSetList == null || accountSetList.isEmpty()) ? null : accountSetList));
        ret.setServiceName(String.join(",", (serviceList == null || serviceList.isEmpty()) ? null : serviceList));
        ret.setBusinessUnitName(row.getBusinessUnitName() == null ? businessUnitName : row.getBusinessUnitName());
        ret.setIndustryName(row.getIndustryName());
        ret.setAreaName(row.getAreaName() == null ? areaName : row.getAreaName());
        ret.setUserList(new ArrayList<>());
        return ret;
    }

    private String getBusinessUnitNameById(String businessUnitId) {

        BusinessUnit businessUnit = businessUnitMapper.selectByPrimaryKey(businessUnitId);
        return businessUnit != null ? businessUnit.getName() : null;
    }

    private String getAreaNameById(String areaId) {
        Area area = areaMapper.selectByPrimaryKey(areaId);
        return area != null ? area.getName() : null;
    }

}